|
1 |
| -/* SPDX-License-Identifier: MIT */ |
2 |
| -/* origin: musl src/math/fmod.c. Ported to generic Rust algorithm in 2025, TG. */ |
3 |
| - |
| 1 | +/* SPDX-License-Identifier: MIT OR Apache-2.0 */ |
4 | 2 | use super::super::{CastFrom, Float, Int, MinInt};
|
5 | 3 |
|
6 | 4 | #[inline]
|
7 | 5 | pub fn fmod<F: Float>(x: F, y: F) -> F {
|
8 |
| - let zero = F::Int::ZERO; |
9 |
| - let one = F::Int::ONE; |
10 |
| - let mut ix = x.to_bits(); |
11 |
| - let mut iy = y.to_bits(); |
12 |
| - let mut ex = x.ex().signed(); |
13 |
| - let mut ey = y.ex().signed(); |
14 |
| - let sx = ix & F::SIGN_MASK; |
| 6 | + let _1 = F::Int::ONE; |
| 7 | + let sx = x.to_bits() & F::SIGN_MASK; |
| 8 | + let ux = x.to_bits() & !F::SIGN_MASK; |
| 9 | + let uy = y.to_bits() & !F::SIGN_MASK; |
15 | 10 |
|
16 |
| - if iy << 1 == zero || y.is_nan() || ex == F::EXP_SAT as i32 { |
| 11 | + // Cases that return NaN: |
| 12 | + // NaN % _ |
| 13 | + // Inf % _ |
| 14 | + // _ % NaN |
| 15 | + // _ % 0 |
| 16 | + let x_nan_or_inf = ux & F::EXP_MASK == F::EXP_MASK; |
| 17 | + let y_nan_or_zero = uy.wrapping_sub(_1) & F::EXP_MASK == F::EXP_MASK; |
| 18 | + if x_nan_or_inf | y_nan_or_zero { |
17 | 19 | return (x * y) / (x * y);
|
18 | 20 | }
|
19 | 21 |
|
20 |
| - if ix << 1 <= iy << 1 { |
21 |
| - if ix << 1 == iy << 1 { |
22 |
| - return F::ZERO * x; |
23 |
| - } |
| 22 | + if ux < uy { |
| 23 | + // |x| < |y| |
24 | 24 | return x;
|
25 | 25 | }
|
26 | 26 |
|
27 |
| - /* normalize x and y */ |
28 |
| - if ex == 0 { |
29 |
| - let i = ix << (F::EXP_BITS + 1); |
30 |
| - ex -= i.leading_zeros() as i32; |
31 |
| - ix <<= -ex + 1; |
32 |
| - } else { |
33 |
| - ix &= F::Int::MAX >> F::EXP_BITS; |
34 |
| - ix |= one << F::SIG_BITS; |
35 |
| - } |
36 |
| - |
37 |
| - if ey == 0 { |
38 |
| - let i = iy << (F::EXP_BITS + 1); |
39 |
| - ey -= i.leading_zeros() as i32; |
40 |
| - iy <<= -ey + 1; |
41 |
| - } else { |
42 |
| - iy &= F::Int::MAX >> F::EXP_BITS; |
43 |
| - iy |= one << F::SIG_BITS; |
44 |
| - } |
45 |
| - |
46 |
| - /* x mod y */ |
47 |
| - while ex > ey { |
48 |
| - let i = ix.wrapping_sub(iy); |
49 |
| - if i >> (F::BITS - 1) == zero { |
50 |
| - if i == zero { |
51 |
| - return F::ZERO * x; |
52 |
| - } |
53 |
| - ix = i; |
54 |
| - } |
| 27 | + let (num, ex) = into_sig_exp::<F>(ux); |
| 28 | + let (div, ey) = into_sig_exp::<F>(uy); |
55 | 29 |
|
56 |
| - ix <<= 1; |
57 |
| - ex -= 1; |
58 |
| - } |
| 30 | + // To compute `(num << ex) % (div << ey)`, first |
| 31 | + // evaluate `rem = (num << (ex - ey)) % div` ... |
| 32 | + let rem = reduction(num, ex - ey, div); |
| 33 | + // ... so the result will be `rem << ey` |
59 | 34 |
|
60 |
| - let i = ix.wrapping_sub(iy); |
61 |
| - if i >> (F::BITS - 1) == zero { |
62 |
| - if i == zero { |
63 |
| - return F::ZERO * x; |
64 |
| - } |
| 35 | + if rem.is_zero() { |
| 36 | + // Return zero with the sign of `x` |
| 37 | + return F::from_bits(sx); |
| 38 | + }; |
65 | 39 |
|
66 |
| - ix = i; |
67 |
| - } |
| 40 | + // We would shift `rem` up by `ey`, but have to stop at `F::SIG_BITS` |
| 41 | + let shift = ey.min(F::SIG_BITS - rem.ilog2()); |
| 42 | + // Anything past that is added to the exponent field |
| 43 | + let bits = (rem << shift) + (F::Int::cast_from(ey - shift) << F::SIG_BITS); |
| 44 | + F::from_bits(sx + bits) |
| 45 | +} |
68 | 46 |
|
69 |
| - let shift = ix.leading_zeros().saturating_sub(F::EXP_BITS); |
70 |
| - ix <<= shift; |
71 |
| - ex -= shift as i32; |
| 47 | +/// Given the bits of a finite float, return a tuple of |
| 48 | +/// - the mantissa with the implicit bit (0 if subnormal, 1 otherwise) |
| 49 | +/// - the additional exponent past 1, (0 for subnormal, 0 or more otherwise) |
| 50 | +fn into_sig_exp<F: Float>(mut bits: F::Int) -> (F::Int, u32) { |
| 51 | + bits &= !F::SIGN_MASK; |
| 52 | + // Subtract 1 from the exponent, clamping at 0 |
| 53 | + let sat = bits.checked_sub(F::IMPLICIT_BIT).unwrap_or(F::Int::ZERO); |
| 54 | + ( |
| 55 | + bits - (sat & F::EXP_MASK), |
| 56 | + u32::cast_from(sat >> F::SIG_BITS), |
| 57 | + ) |
| 58 | +} |
72 | 59 |
|
73 |
| - /* scale result */ |
74 |
| - if ex > 0 { |
75 |
| - ix -= one << F::SIG_BITS; |
76 |
| - ix |= F::Int::cast_from(ex) << F::SIG_BITS; |
77 |
| - } else { |
78 |
| - ix >>= -ex + 1; |
| 60 | +/// Compute the remainder `(x * 2.pow(e)) % y` without overflow. |
| 61 | +fn reduction<I: Int>(mut x: I, e: u32, y: I) -> I { |
| 62 | + x %= y; |
| 63 | + for _ in 0..e { |
| 64 | + x <<= 1; |
| 65 | + x = x.checked_sub(y).unwrap_or(x); |
79 | 66 | }
|
80 |
| - |
81 |
| - ix |= sx; |
82 |
| - |
83 |
| - F::from_bits(ix) |
| 67 | + x |
84 | 68 | }
|
0 commit comments