@@ -29,8 +29,7 @@ use core::f32;
29
29
use core:: ptr:: read_volatile;
30
30
31
31
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 ,
34
33
} ;
35
34
36
35
/*
@@ -91,16 +90,28 @@ pub fn fmaf(x: f32, y: f32, mut z: f32) -> f32 {
91
90
* If result is inexact, and exactly halfway between two float values,
92
91
* we need to adjust the low-order bit in the direction of the error.
93
92
*/
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 ) {
101
100
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) ;
103
116
}
104
- z = adjusted_result as f32 ;
105
- z
106
117
}
0 commit comments