Skip to content
This repository was archived by the owner on Apr 28, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions src/math/fenv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ pub(crate) const FE_UNDERFLOW: i32 = 0;
pub(crate) const FE_INEXACT: i32 = 0;

pub(crate) const FE_TONEAREST: i32 = 0;
pub(crate) const FE_TOWARDZERO: i32 = 0;

#[inline]
pub(crate) fn feclearexcept(_mask: i32) -> i32 {
Expand All @@ -26,8 +25,3 @@ pub(crate) fn fetestexcept(_mask: i32) -> i32 {
pub(crate) fn fegetround() -> i32 {
FE_TONEAREST
}

#[inline]
pub(crate) fn fesetround(_r: i32) -> i32 {
0
}
35 changes: 23 additions & 12 deletions src/math/fmaf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,7 @@ use core::f32;
use core::ptr::read_volatile;

use super::fenv::{
feclearexcept, fegetround, feraiseexcept, fesetround, fetestexcept, FE_INEXACT, FE_TONEAREST,
FE_TOWARDZERO, FE_UNDERFLOW,
feclearexcept, fegetround, feraiseexcept, fetestexcept, FE_INEXACT, FE_TONEAREST, FE_UNDERFLOW,
};

/*
Expand Down Expand Up @@ -91,16 +90,28 @@ pub fn fmaf(x: f32, y: f32, mut z: f32) -> f32 {
* If result is inexact, and exactly halfway between two float values,
* we need to adjust the low-order bit in the direction of the error.
*/
fesetround(FE_TOWARDZERO);
// prevent `vxy + z` from being CSE'd with `xy + z` above
let vxy: f64 = unsafe { read_volatile(&xy) };
let mut adjusted_result: f64 = vxy + z as f64;
fesetround(FE_TONEAREST);
if result == adjusted_result {
ui = adjusted_result.to_bits();
let neg = ui >> 63 != 0;
let err = if neg == (z as f64 > xy) {
xy - result + z as f64
} else {
z as f64 - result + xy
};
if neg == (err < 0.0) {
ui += 1;
adjusted_result = f64::from_bits(ui);
} else {
ui -= 1;
}
f64::from_bits(ui) as f32
}

#[cfg(test)]
mod tests {
#[test]
fn issue_263() {
let a = f32::from_bits(1266679807);
let b = f32::from_bits(1300234242);
let c = f32::from_bits(1115553792);
let expected = f32::from_bits(1501560833);
assert_eq!(super::fmaf(a, b, c), expected);
}
z = adjusted_result as f32;
z
}