libm/math/generic/
fmod.rs
1use crate::support::{CastFrom, Float, Int, MinInt};
3
4#[inline]
5pub fn fmod<F: Float>(x: F, y: F) -> F {
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;
10
11 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 {
19 return (x * y) / (x * y);
20 }
21
22 if ux < uy {
23 return x;
25 }
26
27 let (num, ex) = into_sig_exp::<F>(ux);
28 let (div, ey) = into_sig_exp::<F>(uy);
29
30 let rem = reduction(num, ex - ey, div);
33 if rem.is_zero() {
36 return F::from_bits(sx);
38 };
39
40 let shift = ey.min(F::SIG_BITS - rem.ilog2());
42 let bits = (rem << shift) + (F::Int::cast_from(ey - shift) << F::SIG_BITS);
44 F::from_bits(sx + bits)
45}
46
47fn into_sig_exp<F: Float>(mut bits: F::Int) -> (F::Int, u32) {
51 bits &= !F::SIGN_MASK;
52 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}
59
60fn 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);
66 }
67 x
68}