compiler_builtins/math/libm_math/generic/
fma_wide.rs1use crate::support::{
2 CastFrom, CastInto, DFloat, Float, FpResult, HFloat, IntTy, MinInt, Round, Status,
3};
4
5#[inline]
8pub fn fma_wide_round<F, B>(x: F, y: F, z: F, round: Round) -> FpResult<F>
9where
10 F: Float + HFloat<D = B>,
11 B: Float + DFloat<H = F>,
12 B::Int: CastInto<i32>,
13 i32: CastFrom<i32>,
14{
15 let one = IntTy::<B>::ONE;
16
17 let xy: B = x.widen() * y.widen();
18 let mut result: B = xy + z.widen();
19 let mut ui: B::Int = result.to_bits();
20 let re = result.ex();
21 let zb: B = z.widen();
22
23 let prec_diff = B::SIG_BITS - F::SIG_BITS;
24 let excess_prec = ui & ((one << prec_diff) - one);
25 let halfway = one << (prec_diff - 1);
26
27 if excess_prec != halfway
30 || re == B::EXP_SAT
32 || (result - xy == zb && result - zb == xy)
34 || round != Round::Nearest
36 {
37 let min_inexact_exp = (B::EXP_BIAS as i32 + F::EXP_MIN_SUBNORM) as u32;
38 let max_inexact_exp = (B::EXP_BIAS as i32 + F::EXP_MIN) as u32;
39
40 let mut status = Status::OK;
41
42 if (min_inexact_exp..max_inexact_exp).contains(&re) && status.inexact() {
43 status.set_inexact(false);
45
46 result = xy + z.widen();
47 if status.inexact() {
48 status.set_underflow(true);
49 } else {
50 status.set_inexact(true);
51 }
52 }
53
54 return FpResult {
55 val: result.narrow(),
56 status,
57 };
58 }
59
60 let neg = ui >> (B::BITS - 1) != IntTy::<B>::ZERO;
61 let err = if neg == (zb > xy) {
62 xy - result + zb
63 } else {
64 zb - result + xy
65 };
66 if neg == (err < B::ZERO) {
67 ui += one;
68 } else {
69 ui -= one;
70 }
71
72 FpResult::ok(B::from_bits(ui).narrow())
73}