Nearest-even rounding through guard and sticky bits #
The width-generic rounder Numerics.roundShiftRightEven inspects the guard bit, retained parity,
and sticky bits. Kernels can therefore compress discarded bits before rounding a sum or fused
multiply-add. The proofs below establish how far that compression may go and how it interacts
with alignment and subtraction.
roundShiftRightEven_eq_guard_sticky, fromQuantization.Deterministic.ShiftRight, is the three-bit form of nearest-even rounding that these proofs build on.roundShiftRight_shiftRightJamshows that jamming every bit below positionjinto one sticky bit does not change a later rounding by at leastj + 2bits, under everyMagnitudeRoundingrule.roundShiftRightEven_shiftRightJamis its nearest-even case. Applying this to an addition result needs a further argument relating that result to its jammed value.roundShiftRightEven_mul_two_powandroundShiftRightEven_mul_two_pow_of_lerelate rounding of a scaled value to rounding of the original.shiftRightJam_add_mul_two_powandshiftRightJam_mul_two_pow_subdescribe the jammed quotient of an aligned sum or difference in terms of the two operands, andlog2_shiftRightJamlocates its leading bit.
These statements apply to natural numbers independently of their storage. The fixed-word and limb-array kernels use them to justify their rounding steps.
The guard-and-sticky form #
The number one has no bits above position zero.
The nearest-even quotient is at most the successor of the truncated quotient.
The nearest-even quotient is at least the truncated quotient.
Jamming #
Jamming never decreases the truncated quotient.
Jamming a value with a set bit at or above the jam position gives a nonzero result.
Rounding after a sticky-bit jam agrees with rounding the original value under every rule, provided the rounding keeps at least the guard bit above the jammed position.
The jam preserves the retained bits, the guard bit, and whether any lower bit is set, which are
the only inputs of MagnitudeRounding.increment.
The nearest-even case of roundShiftRight_shiftRightJam: if j + 2 ≤ s, jamming by j and then
rounding by s - j agrees with rounding the original value by s.
Scaling #
Rounding a value scaled by 2^k by k more bits is rounding the value.