Compute ldexp(a+b, scale) with a single rounding error. It is assumed that the result will be subnormal, and care is taken to ensure that double rounding does not occur.
fn add_and_denorm128(a: f128, b: f128, scale: i32) f128
fn add_and_denorm128(a: f128, b: f128, scale: i32) f128 {
var sum = dd_add128(a, b);
// If we are losing at least two bits of accuracy to denormalization,
// then the first lost bit becomes a round bit, and we adjust the
// lowest bit of sum.hi to make it a sticky bit summarizing all the
// bits in sum.lo. With the sticky bit adjusted, the hardware will
// break any ties in the correct direction.
//
// If we are losing only one bit to denormalization, however, we must
// break the ties manually.
if (sum.lo != 0) {
var uhii: u128 = @bitCast(sum.hi);
const bits_lost = -@as(i32, @intCast((uhii >> 112) & 0x7FFF)) - scale + 1;
if ((bits_lost != 1) == (uhii & 1 != 0)) {
const uloi: u128 = @bitCast(sum.lo);
uhii = uhii + 1 - (((uhii ^ uloi) >> 126) & 2);
sum.hi = @bitCast(uhii);
}
}
return math.scalbn(sum.hi, scale);
}