NOTE: Upstream fma.c has been rewritten completely to raise fp exceptions more accurately.
pub fn fma(x: f64, y: f64, z: f64) callconv(.c) f64
pub fn fma(x: f64, y: f64, z: f64) callconv(.c) f64 {
if (!math.isFinite(x) or !math.isFinite(y)) {
return x * y + z;
}
if (!math.isFinite(z)) {
return z;
}
if (x == 0.0 or y == 0.0) {
return x * y + z;
}
if (z == 0.0) {
return x * y;
}
const x1 = math.frexp(x);
const ex = x1.exponent;
const xs = x1.significand;
const x2 = math.frexp(y);
const ey = x2.exponent;
const ys = x2.significand;
const x3 = math.frexp(z);
const ez = x3.exponent;
var zs = x3.significand;
var spread = ex + ey - ez;
if (spread <= 53 * 2) {
zs = math.scalbn(zs, -spread);
} else {
zs = math.copysign(math.floatMin(f64), zs);
}
const xy = dd_mul(xs, ys);
const r = dd_add(xy.hi, zs);
spread = ex + ey;
if (r.hi == 0.0) {
return xy.hi + zs + math.scalbn(xy.lo, spread);
}
const adj = add_adjusted(r.lo, xy.lo);
if (spread + math.ilogb(r.hi) > -1023) {
return math.scalbn(r.hi + adj, spread);
} else {
return add_and_denorm(r.hi, adj, spread);
}
}