@@ -29,8 +29,7 @@ use core::f32;
2929use core:: ptr:: read_volatile;
3030
3131use 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