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