Skip to main content

c/
math_helpers.rs

1// Copyright (c) 2026 Meng Zhuo
2// SPDX-License-Identifier: BSD-3-Clause
3
4
5
6#[inline]
7const fn asuint(f: f32) -> u32 {
8    f.to_bits()
9}
10
11#[inline]
12const fn asfloat(i: u32) -> f32 {
13    f32::from_bits(i)
14}
15
16#[inline]
17const fn asuint64(f: f64) -> u64 {
18    f.to_bits()
19}
20
21#[inline]
22const fn asdouble(i: u64) -> f64 {
23    f64::from_bits(i)
24}
25
26#[inline]
27unsafe fn extract_words(hi: *mut u32, lo: *mut u32, d: f64) {
28    let u = asuint64(d);
29    *hi = (u >> 32) as u32;
30    *lo = u as u32;
31}
32
33#[inline]
34fn get_high_word(d: f64) -> u32 {
35    (asuint64(d) >> 32) as u32
36}
37
38#[inline]
39fn get_low_word(d: f64) -> u32 {
40    asuint64(d) as u32
41}
42
43#[inline]
44unsafe fn insert_words(d: *mut f64, hi: u32, lo: u32) {
45    *d = asdouble(((hi as u64) << 32) | (lo as u64));
46}
47
48#[inline]
49unsafe fn set_high_word(d: *mut f64, hi: u32) {
50    let lo = asuint64(*d) as u32;
51    *d = asdouble(((hi as u64) << 32) | (lo as u64));
52}
53
54#[inline]
55unsafe fn set_low_word(d: *mut f64, lo: u32) {
56    let hi = asuint64(*d) >> 32;
57    *d = asdouble((hi << 32) | (lo as u64));
58}
59
60#[inline]
61unsafe fn get_float_word(f: f32) -> u32 {
62    asuint(f)
63}
64
65#[inline]
66unsafe fn set_float_word(f: *mut f32, w: u32) {
67    *f = asfloat(w);
68}
69
70#[inline]
71fn eval_as_float(x: f32) -> f32 {
72    x
73}
74
75#[inline]
76fn eval_as_double(x: f64) -> f64 {
77    x
78}
79
80#[inline]
81fn fp_barrierf(x: f32) -> f32 {
82    unsafe { core::ptr::read_volatile(&x) }
83}
84
85#[inline]
86fn fp_barrier(x: f64) -> f64 {
87    unsafe { core::ptr::read_volatile(&x) }
88}
89
90#[inline]
91fn fp_force_evalf(x: f32) {
92    unsafe {
93        core::ptr::read_volatile(&x);
94    }
95}
96
97#[inline]
98fn fp_force_eval(x: f64) {
99    unsafe {
100        core::ptr::read_volatile(&x);
101    }
102}
103
104#[inline]
105fn fp_force_evall(x: f64) {
106    unsafe {
107        core::ptr::read_volatile(&x);
108    }
109}
110
111#[inline]
112fn force_eval<T: Copy>(x: T) {
113    unsafe {
114        core::ptr::read_volatile(&x);
115    }
116}
117
118#[inline]
119fn predict_true(x: bool) -> bool {
120    x
121}
122
123#[inline]
124fn predict_false(x: bool) -> bool {
125    x
126}
127
128
129#[inline]
130pub fn __math_invalid(x: f64) -> f64 {
131    if x.is_nan() { return x; }
132    unsafe { feraiseexcept(FE_INVALID); }
133    (x - x) / (x - x)
134}
135
136#[inline]
137pub fn __math_invalidf(x: f32) -> f32 {
138    if x.is_nan() { return x; }
139    unsafe { feraiseexcept(FE_INVALID); }
140    (x - x) / (x - x)
141}
142
143#[inline]
144pub fn __math_divzero(sign: u32) -> f64 {
145    unsafe { feraiseexcept(FE_DIVBYZERO); }
146    let x = if sign != 0 { -1.0f64 } else { 1.0f64 };
147    x / 0.0
148}
149
150#[inline]
151pub fn __math_divzerof(sign: u32) -> f32 {
152    unsafe { feraiseexcept(FE_DIVBYZERO); }
153    let x = if sign != 0 { -1.0f32 } else { 1.0f32 };
154    x / 0.0
155}
156
157#[inline]
158pub fn __math_xflow(sign: u32, y: f64) -> f64 {
159    // musl: (sign ? -y : y) * y  (preserves sign of infinity/zero)
160    if sign != 0 {
161        -y * y
162    } else {
163        y * y
164    }
165}
166
167#[inline]
168pub fn __math_xflowf(sign: u32, y: f32) -> f32 {
169    if sign != 0 {
170        -y * y
171    } else {
172        y * y
173    }
174}
175
176#[inline]
177pub fn __math_oflow(sign: u32) -> f64 {
178    unsafe { feraiseexcept(FE_OVERFLOW | FE_INEXACT); }
179    __math_xflow(sign, 1e231f64)
180}
181
182#[inline]
183pub fn __math_oflowf(sign: u32) -> f32 {
184    unsafe { feraiseexcept(FE_OVERFLOW | FE_INEXACT); }
185    __math_xflowf(sign, 1.7e38f32)
186}
187
188#[inline]
189pub fn __math_uflow(sign: u32) -> f64 {
190    unsafe { feraiseexcept(FE_UNDERFLOW | FE_INEXACT); }
191    __math_xflow(sign, 1e-231f64)
192}
193
194#[inline]
195pub fn __math_uflowf(sign: u32) -> f32 {
196    unsafe { feraiseexcept(FE_UNDERFLOW | FE_INEXACT); }
197    __math_xflowf(sign, 1.2e-38f32)
198}
199
200#[no_mangle]
201pub static mut signgam: c_int = 0;
202
203#[no_mangle]
204pub static mut __signgam: c_int = 0;
205
206pub const FP_NAN: c_int = 0;
207pub const FP_INFINITE: c_int = 1;
208pub const FP_ZERO: c_int = 2;
209pub const FP_SUBNORMAL: c_int = 3;
210pub const FP_NORMAL: c_int = 4;
211
212pub const FP_ILOGB0: c_int = -2147483648i32;
213pub const FP_ILOGBNAN: c_int = 2147483647i32;
214
215#[no_mangle]
216pub unsafe extern "C" fn __fpclassify(x: f64) -> c_int {
217    let u = asuint64(x);
218    let e = (u >> 52) & 0x7ff;
219    if e == 0 {
220        if (u << 1) != 0 { FP_SUBNORMAL } else { FP_ZERO }
221    } else if e == 0x7ff {
222        if (u << 12) != 0 { FP_NAN } else { FP_INFINITE }
223    } else {
224        FP_NORMAL
225    }
226}
227
228#[no_mangle]
229pub unsafe extern "C" fn __fpclassifyf(x: f32) -> c_int {
230    let u = asuint(x);
231    let e = (u >> 23) & 0xff;
232    if e == 0 {
233        if (u << 1) != 0 { FP_SUBNORMAL } else { FP_ZERO }
234    } else if e == 0xff {
235        if (u << 9) != 0 { FP_NAN } else { FP_INFINITE }
236    } else {
237        FP_NORMAL
238    }
239}
240
241#[no_mangle]
242pub fn __signbit(x: f64) -> c_int {
243    ((asuint64(x) >> 63) & 1) as c_int
244}
245
246#[no_mangle]
247pub fn __signbitf(x: f32) -> c_int {
248    ((asuint(x) >> 31) & 1) as c_int
249}
250
251#[inline]
252pub fn is_nan(x: f64) -> bool {
253    let u = asuint64(x);
254    ((u >> 52) & 0x7ff) == 0x7ff && (u << 12) != 0
255}
256
257#[inline]
258pub fn is_nanf(x: f32) -> bool {
259    let u = asuint(x);
260    ((u >> 23) & 0xff) == 0xff && (u << 9) != 0
261}
262
263#[inline]
264pub fn is_inf(x: f64) -> bool {
265    let u = asuint64(x);
266    ((u >> 52) & 0x7ff) == 0x7ff && (u << 12) == 0
267}
268
269#[inline]
270pub fn is_inff(x: f32) -> bool {
271    let u = asuint(x);
272    ((u >> 23) & 0xff) == 0xff && (u << 9) == 0
273}
274
275#[inline]
276pub fn is_finite(x: f64) -> bool {
277    let u = asuint64(x);
278    ((u >> 52) & 0x7ff) != 0x7ff
279}
280
281#[inline]
282pub fn is_finitef(x: f32) -> bool {
283    let u = asuint(x);
284    ((u >> 23) & 0xff) != 0xff
285}
286
287#[inline]
288pub fn toint_value() -> f64 {
289    4503599627370496.0
290}
291
292#[inline]
293pub fn tointf_value() -> f32 {
294    8388608.0f32
295}