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

Commit 6fea5fb

Browse files
committed
Fix fmaf not to depend on FE_TOWARDZERO
Ported from upstream musl commit 4f3d346bffdf9ed2b1803653643dc31242490944 Fixes #263
1 parent d6d8a16 commit 6fea5fb

File tree

2 files changed

+23
-18
lines changed

2 files changed

+23
-18
lines changed

src/math/fenv.rs

-6
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ pub(crate) const FE_UNDERFLOW: i32 = 0;
55
pub(crate) const FE_INEXACT: i32 = 0;
66

77
pub(crate) const FE_TONEAREST: i32 = 0;
8-
pub(crate) const FE_TOWARDZERO: i32 = 0;
98

109
#[inline]
1110
pub(crate) fn feclearexcept(_mask: i32) -> i32 {
@@ -26,8 +25,3 @@ pub(crate) fn fetestexcept(_mask: i32) -> i32 {
2625
pub(crate) fn fegetround() -> i32 {
2726
FE_TONEAREST
2827
}
29-
30-
#[inline]
31-
pub(crate) fn fesetround(_r: i32) -> i32 {
32-
0
33-
}

src/math/fmaf.rs

+23-12
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,7 @@ use core::f32;
2929
use core::ptr::read_volatile;
3030

3131
use super::fenv::{
32-
feclearexcept, fegetround, feraiseexcept, fesetround, fetestexcept, FE_INEXACT, FE_TONEAREST,
33-
FE_TOWARDZERO, FE_UNDERFLOW,
32+
feclearexcept, fegetround, feraiseexcept, fetestexcept, FE_INEXACT, FE_TONEAREST, FE_UNDERFLOW,
3433
};
3534

3635
/*
@@ -91,16 +90,28 @@ pub fn fmaf(x: f32, y: f32, mut z: f32) -> f32 {
9190
* If result is inexact, and exactly halfway between two float values,
9291
* we need to adjust the low-order bit in the direction of the error.
9392
*/
94-
fesetround(FE_TOWARDZERO);
95-
// prevent `vxy + z` from being CSE'd with `xy + z` above
96-
let vxy: f64 = unsafe { read_volatile(&xy) };
97-
let mut adjusted_result: f64 = vxy + z as f64;
98-
fesetround(FE_TONEAREST);
99-
if result == adjusted_result {
100-
ui = adjusted_result.to_bits();
93+
let neg = ui >> 63 != 0;
94+
let err = if neg == (z as f64 > xy) {
95+
xy - result + z as f64
96+
} else {
97+
z as f64 - result + xy
98+
};
99+
if neg == (err < 0.0) {
101100
ui += 1;
102-
adjusted_result = f64::from_bits(ui);
101+
} else {
102+
ui -= 1;
103+
}
104+
f64::from_bits(ui) as f32
105+
}
106+
107+
#[cfg(test)]
108+
mod tests {
109+
#[test]
110+
fn issue_263() {
111+
let a = f32::from_bits(1266679807);
112+
let b = f32::from_bits(1300234242);
113+
let c = f32::from_bits(1115553792);
114+
let expected = f32::from_bits(1501560833);
115+
assert_eq!(super::fmaf(a, b, c), expected);
103116
}
104-
z = adjusted_result as f32;
105-
z
106117
}

0 commit comments

Comments
 (0)