|
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