Skip to content

Commit 70fa7ef

Browse files
committed
Add newlib fmodf
1 parent 45170c2 commit 70fa7ef

File tree

1 file changed

+140
-0
lines changed

1 file changed

+140
-0
lines changed

Diff for: src/math/fmodf.rs

+140
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
/* ef_fmod.c -- float version of e_fmod.c.
2+
* Conversion to float by Ian Lance Taylor, Cygnus Support, [email protected].
3+
*/
4+
5+
/*
6+
* ====================================================
7+
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
8+
*
9+
* Developed at SunPro, a Sun Microsystems, Inc. business.
10+
* Permission to use, copy, modify, and distribute this
11+
* software is freely granted, provided that this notice
12+
* is preserved.
13+
* ====================================================
14+
*/
15+
16+
const ONE: f32 = 1.0f32;
17+
const ZERO: [f32; 2] = [0.0f32, -0.0];
18+
19+
/// Return `x mod y` in exact arithmetic.
20+
///
21+
/// Method: shift and subtract
22+
#[inline]
23+
#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)]
24+
pub fn fmodf(x: f32, y: f32) -> f32 {
25+
use super::fdlibm::{
26+
FLT_UWORD_IS_FINITE, FLT_UWORD_IS_NAN, FLT_UWORD_IS_SUBNORMAL, FLT_UWORD_IS_ZERO,
27+
};
28+
const U32_BITS: u8 = 32;
29+
let mut n: i32;
30+
let mut hx: u32;
31+
let mut hy: u32;
32+
let mut hz: i32;
33+
let mut ix: i32;
34+
let mut iy: i32;
35+
let sx: u32;
36+
let mut i: i32;
37+
38+
hx = x.to_bits();
39+
sx = hx & 0x80000000; /* sign of x */
40+
hx ^= sx; /* |x| */
41+
hy = y.to_bits() & 0x7fffffff; /* |y| */
42+
43+
/* purge off exception values */
44+
if FLT_UWORD_IS_ZERO(hy) || !FLT_UWORD_IS_FINITE(hx) || FLT_UWORD_IS_NAN(hy) {
45+
return (x * y) / (x * y);
46+
}
47+
if hx < hy {
48+
return x; /* |x|<|y| return x */
49+
}
50+
if hx == hy {
51+
return ZERO[sx as usize >> (U32_BITS - 1)]; /* |x|=|y| return x*0 */
52+
}
53+
54+
/* Note: y cannot be zero if we reach here. */
55+
56+
/* determine ix = ilogb(x) */
57+
if FLT_UWORD_IS_SUBNORMAL(hx) {
58+
/* subnormal x */
59+
ix = -126;
60+
i = (hx << 8) as i32;
61+
while i > 0 {
62+
ix -= 1;
63+
i <<= 1;
64+
}
65+
} else {
66+
ix = (hx >> 23) as i32 - 127;
67+
}
68+
69+
/* determine iy = ilogb(y) */
70+
if FLT_UWORD_IS_SUBNORMAL(hy) {
71+
/* subnormal y */
72+
iy = -126;
73+
i = (hy << 8) as i32;
74+
while i >= 0 {
75+
iy -= 1;
76+
i <<= 1;
77+
}
78+
} else {
79+
iy = (hy >> 23) as i32 - 127;
80+
}
81+
82+
/* set up {hx,lx}, {hy,ly} and align y to x */
83+
if ix >= -126 {
84+
hx = 0x0080_0000 | (0x007f_ffff & hx);
85+
} else {
86+
/* subnormal x, shift x to normal */
87+
n = -126 - ix;
88+
hx <<= n;
89+
}
90+
if iy >= -126 {
91+
hy = 0x0080_0000 | (0x007f_ffff & hy);
92+
} else {
93+
/* subnormal y, shift y to normal */
94+
n = -126 - iy;
95+
hy <<= n;
96+
}
97+
98+
/* fix point fmod */
99+
n = ix - iy;
100+
while n != 0 {
101+
hz = hx.wrapping_sub(hy) as i32;
102+
if hz < 0 {
103+
hx += hx;
104+
} else {
105+
if hz == 0 {
106+
/* return sign(x)*0 */
107+
return ZERO[sx as usize >> (U32_BITS - 1)];
108+
}
109+
hx = (hz + hz) as u32;
110+
}
111+
n -= 1;
112+
}
113+
hz = hx.wrapping_sub(hy) as i32;
114+
if hz >= 0 {
115+
hx = hz as u32;
116+
}
117+
118+
/* convert back to floating value and restore the sign */
119+
if hx == 0 {
120+
/* return sign(x)*0 */
121+
return ZERO[sx as usize >> (U32_BITS - 1)];
122+
}
123+
while hx < 0x0080_0000 {
124+
/* normalize x */
125+
hx += hx;
126+
iy -= 1;
127+
}
128+
if iy >= -126 {
129+
/* normalize output */
130+
hx = (hx.wrapping_sub(0x0080_0000)) | ((iy + 127) << 23) as u32;
131+
f32::from_bits(hx | sx)
132+
} else {
133+
/* subnormal output */
134+
/* If denormals are not supported, this code will generate a zero representation. */
135+
n = -126 - iy;
136+
hx >>= n;
137+
/* create necessary signal */
138+
f32::from_bits(hx | sx) * ONE
139+
}
140+
}

0 commit comments

Comments
 (0)