Skip to main content

c/
math_sqrtfmod.rs

1// Translated from musl: sqrt.c, sqrtf.c, fmod.c, fmodf.c, sqrt_data.c
2// Uses only integer/bit ops and f64::from_bits/to_bits.
3// No Rust float methods except final return.
4
5// ============================================================
6// sqrt_data: __rsqrt_tab lookup table
7// ============================================================
8
9const RSQRT_TAB: [u16; 128] = [
10    0xb451,0xb2f0,0xb196,0xb044,0xaef9,0xadb6,0xac79,0xab43,
11    0xaa14,0xa8eb,0xa7c8,0xa6aa,0xa592,0xa480,0xa373,0xa26b,
12    0xa168,0xa06a,0x9f70,0x9e7b,0x9d8a,0x9c9d,0x9bb5,0x9ad1,
13    0x99f0,0x9913,0x983a,0x9765,0x9693,0x95c4,0x94f8,0x9430,
14    0x936b,0x92a9,0x91ea,0x912e,0x9075,0x8fbe,0x8f0a,0x8e59,
15    0x8daa,0x8cfe,0x8c54,0x8bac,0x8b07,0x8a64,0x89c4,0x8925,
16    0x8889,0x87ee,0x8756,0x86c0,0x862b,0x8599,0x8508,0x8479,
17    0x83ec,0x8361,0x82d8,0x8250,0x81c9,0x8145,0x80c2,0x8040,
18    0xff02,0xfd0e,0xfb25,0xf947,0xf773,0xf5aa,0xf3ea,0xf234,
19    0xf087,0xeee3,0xed47,0xebb3,0xea27,0xe8a3,0xe727,0xe5b2,
20    0xe443,0xe2dc,0xe17a,0xe020,0xdecb,0xdd7d,0xdc34,0xdaf1,
21    0xd9b3,0xd87b,0xd748,0xd61a,0xd4f1,0xd3cd,0xd2ad,0xd192,
22    0xd07b,0xcf69,0xce5b,0xcd51,0xcc4a,0xcb48,0xca4a,0xc94f,
23    0xc858,0xc764,0xc674,0xc587,0xc49d,0xc3b7,0xc2d4,0xc1f4,
24    0xc116,0xc03c,0xbf65,0xbe90,0xbdbe,0xbcef,0xbc23,0xbb59,
25    0xba91,0xb9cc,0xb90a,0xb84a,0xb78c,0xb6d0,0xb617,0xb560,
26];
27
28// ============================================================
29// sqrt helpers
30// ============================================================
31
32#[inline]
33fn mul32(a: u32, b: u32) -> u32 {
34    ((a as u64 * b as u64) >> 32) as u32
35}
36
37#[inline]
38fn mul64(a: u64, b: u64) -> u64 {
39    let ahi = a >> 32;
40    let alo = a & 0xffffffff;
41    let bhi = b >> 32;
42    let blo = b & 0xffffffff;
43    ahi * bhi + (ahi * blo >> 32) + (alo * bhi >> 32)
44}
45
46// ============================================================
47// sqrt
48// ============================================================
49
50#[no_mangle]
51pub extern "C" fn sqrt(x: f64) -> f64 {
52    let ix = asuint64(x);
53    let mut top = ix >> 52;
54
55    // special case handling
56    if predict_false(top.wrapping_sub(0x001) >= 0x7ff - 0x001) {
57        // x < 0x1p-1022 or inf or nan
58        if ix.wrapping_mul(2) == 0 {
59            return x;
60        }
61        if ix == 0x7ff0000000000000 {
62            return x;
63        }
64        if ix > 0x7ff0000000000000 {
65            return __math_invalid(x);
66        }
67        // x is subnormal, normalize it
68        let ix2 = asuint64(x * p2d(52));
69        top = ix2 >> 52;
70        top -= 52;
71        // use normalized ix
72        return sqrt_inner(ix2, top);
73    }
74    sqrt_inner(ix, top)
75}
76
77#[inline]
78fn sqrt_inner(ix: u64, top: u64) -> f64 {
79    let mut top = top;
80    let mut m;
81
82    let even = top & 1;
83    m = (ix << 11) | 0x8000000000000000u64;
84    if even != 0 {
85        m >>= 1;
86    }
87    top = (top + 0x3ff) >> 1;
88
89    let three = 0xc0000000u64;
90
91    let i = ((ix >> 46) % 128) as usize;
92    let mut r = (RSQRT_TAB[i] as u64) << 16;
93    // |r sqrt(m) - 1| < 0x1.fdp-9
94    let mut s = mul32((m >> 32) as u32, r as u32) as u64;
95    // |s/sqrt(m) - 1| < 0x1.fdp-9
96    let mut d = mul32(s as u32, r as u32) as u64;
97    let mut u = three.wrapping_sub(d);
98    r = (mul32(r as u32, u as u32) as u64) << 1;
99    // |r sqrt(m) - 1| < 0x1.7bp-16
100    s = (mul32(s as u32, u as u32) as u64) << 1;
101    // |s/sqrt(m) - 1| < 0x1.7bp-16
102    d = mul32(s as u32, r as u32) as u64;
103    u = three.wrapping_sub(d);
104    r = (mul32(r as u32, u as u32) as u64) << 1;
105    // |r sqrt(m) - 1| < 0x1.3704p-29
106    r = r << 32;
107    s = mul64(m, r);
108    d = mul64(s, r);
109    u = (three << 32).wrapping_sub(d);
110    s = mul64(s, u);
111    // -0x1p-57 < s - sqrt(m) < 0x1.8001p-61
112    s = (s.wrapping_sub(2)) >> 9;
113
114    let d0 = m.wrapping_shl(42).wrapping_sub(s.wrapping_mul(s));
115    let d1 = s.wrapping_sub(d0);
116    let d2 = d1.wrapping_add(s).wrapping_add(1);
117    let s = s.wrapping_add((d1 >> 63) & 1);
118    let mut s = s & 0x000fffffffffffff;
119    s |= top << 52;
120    let mut y = asdouble(s);
121    // handle rounding modes and inexact exception
122    let tiny = if predict_false(d2 == 0) { 0u64 } else { 0x0010000000000000u64 };
123    let tiny = tiny | ((d1 ^ d2) & 0x8000000000000000);
124    let t = asdouble(tiny);
125    y = eval_as_double(y + t);
126    y
127}
128
129// ============================================================
130// sqrtf
131// ============================================================
132
133#[no_mangle]
134pub extern "C" fn sqrtf(x: f32) -> f32 {
135    let ix = asuint(x);
136    if predict_false(ix.wrapping_sub(0x00800000) >= 0x7f800000 - 0x00800000) {
137        // x < 0x1p-126 or inf or nan
138        if ix.wrapping_mul(2) == 0 {
139            return x;
140        }
141        if ix == 0x7f800000 {
142            return x;
143        }
144        if ix > 0x7f800000 {
145            return __math_invalidf(x);
146        }
147        // x is subnormal, normalize it
148        let ix2 = asuint(x * p2f(23));
149        return sqrtf_inner(ix2.wrapping_sub(23 << 23));
150    }
151    sqrtf_inner(ix)
152}
153
154#[inline]
155fn sqrtf_inner(ix: u32) -> f32 {
156    let even = ix & 0x00800000;
157    let m1 = (ix << 8) | 0x80000000u32;
158    let m0 = (ix << 7) & 0x7fffffff;
159    let m = if even != 0 { m0 } else { m1 };
160
161    // 2^e is the exponent part of the return value
162    let mut ey = ix >> 1;
163    ey = ey.wrapping_add(0x3f800000 >> 1);
164    ey &= 0x7f800000;
165
166    let three = 0xc0000000u32;
167    let i = ((ix >> 17) % 128) as usize;
168    let mut r = (RSQRT_TAB[i] as u32) << 16;
169    let mut s = mul32(m, r);
170    let mut d = mul32(s, r);
171    let mut u = three.wrapping_sub(d);
172    r = mul32(r, u) << 1;
173    s = mul32(s, u) << 1;
174    d = mul32(s, r);
175    u = three.wrapping_sub(d);
176    s = mul32(s, u);
177    // -0x1.03p-28 < s/sqrt(m) - 1 < 0x1.fp-31
178    s = (s.wrapping_sub(1)) >> 6;
179
180    let d0 = m.wrapping_shl(16).wrapping_sub(s.wrapping_mul(s));
181    let d1 = s.wrapping_sub(d0);
182    let d2 = d1.wrapping_add(s).wrapping_add(1);
183    let s = s.wrapping_add((d1 >> 31) & 1);
184    let mut s = s & 0x007fffff;
185    s |= ey;
186    let mut y = asfloat(s);
187    // handle rounding and inexact exception
188    let tiny = if predict_false(d2 == 0) { 0u32 } else { 0x01000000u32 };
189    let tiny = tiny | ((d1 ^ d2) & 0x80000000);
190    let t = asfloat(tiny);
191    y = eval_as_float(y + t);
192    y
193}
194
195// ============================================================
196// fmod
197// ============================================================
198
199#[no_mangle]
200pub extern "C" fn fmod(x: f64, y: f64) -> f64 {
201    let uxi = asuint64(x);
202    let uyi = asuint64(y);
203    let ex = ((uxi >> 52) & 0x7ff) as i32;
204    let ey = ((uyi >> 52) & 0x7ff) as i32;
205    let sx = uxi >> 63;
206
207    if uyi << 1 == 0 || is_nan(y) || ex == 0x7ff {
208        return (x * y) / (x * y);
209    }
210    if uxi << 1 <= uyi << 1 {
211        if uxi << 1 == uyi << 1 {
212            return 0.0 * x;
213        }
214        return x;
215    }
216
217    // normalize x and y
218    let mut uxi = uxi;
219    let mut uyi = uyi;
220    let mut ex = ex;
221    let mut ey = ey;
222
223    if ex == 0 {
224        let mut i = uxi << 12;
225        while (i as i64) >= 0 {
226            ex -= 1;
227            i <<= 1;
228        }
229        uxi <<= (-ex + 1) as u64;
230    } else {
231        uxi &= (-1i64 as u64) >> 12;
232        uxi |= 1u64 << 52;
233    }
234    if ey == 0 {
235        let mut i = uyi << 12;
236        while (i as i64) >= 0 {
237            ey -= 1;
238            i <<= 1;
239        }
240        uyi <<= (-ey + 1) as u64;
241    } else {
242        uyi &= (-1i64 as u64) >> 12;
243        uyi |= 1u64 << 52;
244    }
245
246    // x mod y
247    while ex > ey {
248        let i = uxi.wrapping_sub(uyi);
249        if (i as i64) >= 0 {
250            if i == 0 {
251                return 0.0 * x;
252            }
253            uxi = i;
254        }
255        uxi <<= 1;
256        ex -= 1;
257    }
258    let i = uxi.wrapping_sub(uyi);
259    if (i as i64) >= 0 {
260        if i == 0 {
261            return 0.0 * x;
262        }
263        uxi = i;
264    }
265    while uxi >> 52 == 0 {
266        uxi <<= 1;
267        ex -= 1;
268    }
269
270    // scale result
271    if ex > 0 {
272        uxi -= 1u64 << 52;
273        uxi |= (ex as u64) << 52;
274    } else {
275        uxi >>= (-ex + 1) as u64;
276    }
277    uxi |= sx << 63;
278    asdouble(uxi)
279}
280
281// ============================================================
282// fmodf
283// ============================================================
284
285#[no_mangle]
286pub extern "C" fn fmodf(x: f32, y: f32) -> f32 {
287    let uxi = asuint(x);
288    let uyi = asuint(y);
289    let ex = ((uxi >> 23) & 0xff) as i32;
290    let ey = ((uyi >> 23) & 0xff) as i32;
291    let sx = uxi & 0x80000000;
292
293    if uyi << 1 == 0 || is_nanf(y) || ex == 0xff {
294        return (x * y) / (x * y);
295    }
296    if uxi << 1 <= uyi << 1 {
297        if uxi << 1 == uyi << 1 {
298            return 0.0f32 * x;
299        }
300        return x;
301    }
302
303    // normalize x and y
304    let mut uxi = uxi;
305    let mut uyi = uyi;
306    let mut ex = ex;
307    let mut ey = ey;
308
309    if ex == 0 {
310        let mut i = uxi << 9;
311        while (i as i32) >= 0 {
312            ex -= 1;
313            i <<= 1;
314        }
315        uxi <<= (-ex + 1) as u32;
316    } else {
317        uxi &= (-1i32 as u32) >> 9;
318        uxi |= 1u32 << 23;
319    }
320    if ey == 0 {
321        let mut i = uyi << 9;
322        while (i as i32) >= 0 {
323            ey -= 1;
324            i <<= 1;
325        }
326        uyi <<= (-ey + 1) as u32;
327    } else {
328        uyi &= (-1i32 as u32) >> 9;
329        uyi |= 1u32 << 23;
330    }
331
332    // x mod y
333    while ex > ey {
334        let i = uxi.wrapping_sub(uyi);
335        if (i as i32) >= 0 {
336            if i == 0 {
337                return 0.0f32 * x;
338            }
339            uxi = i;
340        }
341        uxi <<= 1;
342        ex -= 1;
343    }
344    let i = uxi.wrapping_sub(uyi);
345    if (i as i32) >= 0 {
346        if i == 0 {
347            return 0.0f32 * x;
348        }
349        uxi = i;
350    }
351    while uxi >> 23 == 0 {
352        uxi <<= 1;
353        ex -= 1;
354    }
355
356    // scale result up
357    if ex > 0 {
358        uxi -= 1u32 << 23;
359        uxi |= (ex as u32) << 23;
360    } else {
361        uxi >>= (-ex + 1) as u32;
362    }
363    uxi |= sx;
364    asfloat(uxi)
365}