Skip to content
This repository was archived by the owner on Apr 28, 2025. It is now read-only.

Commit 47029ed

Browse files
committed
Reimplement the generic fmod
1 parent 3020d64 commit 47029ed

File tree

3 files changed

+49
-65
lines changed

3 files changed

+49
-65
lines changed

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#![allow(clippy::float_cmp)]
1313
#![allow(clippy::int_plus_one)]
1414
#![allow(clippy::many_single_char_names)]
15+
#![allow(clippy::just_underscores_and_digits)]
1516
#![allow(clippy::mixed_case_hex_literals)]
1617
#![allow(clippy::needless_late_init)]
1718
#![allow(clippy::needless_return)]

src/math/generic/fmod.rs

Lines changed: 44 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,84 +1,63 @@
1-
/* SPDX-License-Identifier: MIT */
2-
/* origin: musl src/math/fmod.c. Ported to generic Rust algorithm in 2025, TG. */
3-
41
use super::super::{CastFrom, Float, Int, MinInt};
52

3+
/// Given the bits of a positive float, clamp the exponent field to [0,1]
4+
fn collapse_exponent<F: Float>(bits: F::Int) -> F::Int {
5+
let sig = bits & F::SIG_MASK;
6+
if sig == bits { sig } else { sig | F::IMPLICIT_BIT }
7+
}
8+
9+
/// Computes (x << e) % y
10+
fn reduction<I: Int>(mut x: I, e: u32, y: I) -> I {
11+
x %= y;
12+
for _ in 0..e {
13+
x <<= 1;
14+
x = x.checked_sub(y).unwrap_or(x);
15+
}
16+
x
17+
}
18+
619
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
720
pub fn fmod<F: Float>(x: F, y: F) -> F {
8-
let zero = F::Int::ZERO;
9-
let one = F::Int::ONE;
21+
let _1 = F::Int::ONE;
1022
let mut ix = x.to_bits();
1123
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;
15-
16-
if iy << 1 == zero || y.is_nan() || ex == F::EXP_SAT as i32 {
17-
return (x * y) / (x * y);
18-
}
1924

20-
if ix << 1 <= iy << 1 {
21-
if ix << 1 == iy << 1 {
22-
return F::ZERO * x;
23-
}
24-
return x;
25-
}
25+
let sx = ix & F::SIGN_MASK;
26+
ix &= !F::SIGN_MASK;
27+
iy &= !F::SIGN_MASK;
2628

27-
/* normalize x and y */
28-
if ex == 0 {
29-
let i = ix << F::EXP_BITS;
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;
29+
if ix >= F::EXP_MASK {
30+
// x is nan or inf
31+
return F::NAN;
3532
}
3633

37-
if ey == 0 {
38-
let i = iy << F::EXP_BITS;
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;
34+
if iy.wrapping_sub(_1) >= F::EXP_MASK {
35+
// y is nan or zero
36+
return F::NAN;
4437
}
4538

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-
}
55-
56-
ix <<= 1;
57-
ex -= 1;
58-
}
39+
if ix < iy {
40+
// |x| < |y|
41+
return x;
42+
};
5943

60-
let i = ix.wrapping_sub(iy);
61-
if i >> (F::BITS - 1) == zero {
62-
if i == zero {
63-
return F::ZERO * x;
64-
}
44+
let ex: u32 = x.ex().saturating_sub(1);
45+
let ey: u32 = y.ex().saturating_sub(1);
6546

66-
ix = i;
67-
}
47+
let num = collapse_exponent::<F>(ix);
48+
let div = collapse_exponent::<F>(iy);
6849

69-
let shift = ix.leading_zeros().saturating_sub(F::EXP_BITS);
70-
ix <<= shift;
71-
ex -= shift as i32;
50+
let num = reduction(num, ex - ey, div);
7251

73-
/* scale result */
74-
if ex > 0 {
75-
ix -= one << F::SIG_BITS;
76-
ix |= F::Int::cast_from(ex) << F::SIG_BITS;
52+
if num.is_zero() {
53+
F::from_bits(sx)
7754
} else {
78-
ix >>= -ex + 1;
79-
}
55+
let ilog = num.ilog2();
56+
let shift = (ey + ilog).min(F::SIG_BITS) - ilog;
57+
let scale = (ey + ilog).saturating_sub(F::SIG_BITS);
8058

81-
ix |= sx;
82-
83-
F::from_bits(ix)
59+
let normalized = num << shift;
60+
let scaled = normalized + (F::Int::cast_from(scale) << F::SIG_BITS);
61+
F::from_bits(sx | scaled)
62+
}
8463
}

src/math/support/int_traits.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ pub trait Int:
4040
+ PartialOrd
4141
+ ops::AddAssign
4242
+ ops::SubAssign
43+
+ ops::MulAssign
44+
+ ops::DivAssign
45+
+ ops::RemAssign
4346
+ ops::BitAndAssign
4447
+ ops::BitOrAssign
4548
+ ops::BitXorAssign
@@ -51,6 +54,7 @@ pub trait Int:
5154
+ ops::Sub<Output = Self>
5255
+ ops::Mul<Output = Self>
5356
+ ops::Div<Output = Self>
57+
+ ops::Rem<Output = Self>
5458
+ ops::Shl<i32, Output = Self>
5559
+ ops::Shl<u32, Output = Self>
5660
+ ops::Shr<i32, Output = Self>

0 commit comments

Comments
 (0)