|
1 | 1 | use super::super::fenv::{FE_TONEAREST, fegetround}; |
2 | | -use super::super::{CastFrom, CastInto, DFloat, Float, HFloat, Int, IntTy, MinInt}; |
| 2 | +use super::super::{CastFrom, CastInto, DFloat, Float, HFloat, IntTy, MinInt}; |
3 | 3 |
|
4 | 4 | /// FMA implementation when a hardware-backed larger float type is available. |
5 | 5 | pub fn fma_big<F, B>(x: F, y: F, z: F) -> F |
6 | 6 | where |
7 | 7 | F: Float + HFloat<D = B>, |
8 | 8 | B: Float + DFloat<H = F>, |
9 | | - // F: Float + CastInto<B>, |
10 | | - // B: Float + CastInto<F> + CastFrom<F>, |
11 | 9 | B::Int: CastInto<i32>, |
12 | 10 | i32: CastFrom<i32>, |
13 | 11 | { |
14 | 12 | let one = IntTy::<B>::ONE; |
15 | 13 |
|
16 | | - let xy: B; |
17 | | - let result: B; |
18 | | - let mut ui: B::Int; |
19 | | - let e: i32; |
20 | | - |
21 | | - xy = x.widen() * y.widen(); |
22 | | - result = xy + z.widen(); |
23 | | - ui = result.to_bits(); |
24 | | - e = result.exp().signed(); |
| 14 | + let xy: B = x.widen() * y.widen(); |
| 15 | + let result: B = xy + z.widen(); |
| 16 | + let mut ui: B::Int = result.to_bits(); |
| 17 | + let re = result.exp(); |
25 | 18 | let zb: B = z.widen(); |
26 | 19 |
|
27 | 20 | let prec_diff = B::SIG_BITS - F::SIG_BITS; |
28 | 21 | let excess_prec = ui & ((one << prec_diff) - one); |
29 | | - let x = one << (prec_diff - 1); |
30 | | - |
31 | | - // Common case: the larger precision is fine |
32 | | - if excess_prec != x |
33 | | - || e == i32::cast_from(F::EXP_MAX) |
| 22 | + let halfway = one << (prec_diff - 1); |
| 23 | + |
| 24 | + // Common case: the larger precision is fine if... |
| 25 | + // This is not a halfway case |
| 26 | + if excess_prec != halfway |
| 27 | + // Or the result is NaN |
| 28 | + || re == B::EXP_MAX |
| 29 | + // Or the result is exact |
34 | 30 | || (result - xy == zb && result - zb == xy) |
| 31 | + // Or the mode is something other than round to nearest |
35 | 32 | || fegetround() != FE_TONEAREST |
36 | 33 | { |
37 | 34 | // TODO: feclearexcept |
|
0 commit comments