TorchLean API

FloatLib.Floats.Formats.BinaryInterchange.Operations.Proof.RoundToIntegral

Integral-rounding contracts #

The unbounded dyadic-to-integer kernel is related to the usual nearest-even, nearest-away, floor, ceiling, truncation, and away-from-zero semantics. The floating-point wrapper then records exactly when fractional bits were discarded and exposes the exceptional branches.

For IEEE encodings with fmt.fracWidth ≤ fmt.maxNormalExponent, the selected integer is exactly representable. This condition holds for the IEEE interchange formats. On finite inputs, roundToIntegral then denotes the integer selected by the rounding direction and reports no overflow. Truncation toward zero needs no such range condition: its result cannot exceed the input magnitude. Nearest-away rounding is roundToIntegralTiesToAway of IEEE 754-2019, Section 5.9, and it is Flocq's nearestChoice with the tie choice nearestAwayChoice.

References #

@[simp]

Exact zero rounds to integer zero in every direction.

Nearest-even integer rounding has its usual mathematical meaning, independently of the stored dyadic exponent or magnitude.

Rounding toward positive infinity computes the mathematical ceiling.

Rounding toward negative infinity computes the mathematical floor.

Rounding toward zero truncates the exact dyadic: nonnegative values use floor and negative values use ceiling.

Nearest-away integer rounding is Flocq's nearest rounding with ties away from zero, independently of the stored dyadic exponent or magnitude.

Rounding away from zero takes the ceiling of a nonnegative exact dyadic and the floor of a negative one.

theorem FloatLib.Floats.Formats.BinaryInterchange.Model.dyadicIsIntegral_ofNat (negative : Bool) (significand exponent : ℕ) :
dyadicIsIntegral { negative := negative, significand := significand, exponent := Int.ofNat exponent } = true

A dyadic with a nonnegative exponent is already an integer.

@[simp]
theorem FloatLib.Floats.Formats.BinaryInterchange.Model.dyadicIsIntegral_zero (negative : Bool) (exponent : ℤ) :
dyadicIsIntegral { negative := negative, significand := 0, exponent := exponent } = true

Dyadic zero is integral independently of its stored sign and exponent.

An exact dyadic is integral exactly when no negative binary exponent leaves a fractional bit.

For exponent -(shift + 1), this says that 2^(shift + 1) divides the significand. A nonnegative exponent is always integral.

@[simp]

Integral rounding with status := true delivers the value of integral rounding.

theorem FloatLib.Floats.Formats.BinaryInterchange.Model.roundToIntegral_inexact_iff {fmt : FloatFormat} (value : Model fmt) (mode : IEEERoundingMode) (exact : Numerics.Dyadic) (hvalue : value.exactValue = ExactValue.finite exact) :
(value.roundToIntegral mode true).status.inexact = true ↔ match exact.exponent with | Int.ofNat a => False | Int.negSucc shift => ¬2 ^ (shift + 1) ∣ exact.significand

On finite input, roundToIntegral raises inexact exactly when a negative binary exponent leaves at least one fractional bit.

theorem FloatLib.Floats.Formats.BinaryInterchange.Model.roundToIntegral_status_of_infinity {fmt : FloatFormat} (value : Model fmt) (mode : IEEERoundingMode) (negative : Bool) (hvalue : value.exactValue = ExactValue.infinity negative) :
value.roundToIntegral mode true = { value := value, status := Numerics.IEEEStatus.clear, ternary := Ordering.eq }

roundToIntegral returns either infinity unchanged, with clear status.

theorem FloatLib.Floats.Formats.BinaryInterchange.Model.roundToIntegral_status_of_nan {fmt : FloatFormat} (value : Model fmt) (mode : IEEERoundingMode) (negative signaling : Bool) (payload : ℕ) (hvalue : value.exactValue = ExactValue.nan negative signaling payload) :
value.roundToIntegral mode true = { value := value.quietNaN, status := { invalid := signaling }, ternary := Ordering.eq }

roundToIntegral quiets a NaN and raises invalid exactly when it was signaling.

Representability of the rounded integer #

Every rounding direction lands at or above the floor of the exact value.

Every rounding direction lands at or below the ceiling of the exact value.

theorem FloatLib.Floats.Formats.BinaryInterchange.Model.abs_roundDyadicToInt_le_two_pow_of_exponent_neg (mode : IEEERoundingMode) (value : Numerics.Dyadic) (fracWidth : ℕ) (hsig : value.significand < 2 ^ (fracWidth + 1)) (hexp : value.exponent < 0) :
|roundDyadicToInt mode value| ≤ 2 ^ fracWidth

If the significand is below 2^(fracWidth + 1) and the binary exponent is negative, the rounded integer has magnitude at most 2^fracWidth.

theorem FloatLib.Floats.Formats.BinaryInterchange.Model.roundToIntegral_status_of_finite {fmt : FloatFormat} (value : Model fmt) (mode : IEEERoundingMode) (exact : Numerics.Dyadic) (hvalue : value.exactValue = ExactValue.finite exact) :
value.roundToIntegral mode true = have coefficient := roundDyadicToInt mode exact; have rounded := if (coefficient == 0) = true then zero fmt exact.negative else Internal.Directed.roundDyadic fmt mode (Numerics.Dyadic.ofScaledInt coefficient 0); have encodingStatus := dyadicRoundingStatus fmt mode (Numerics.Dyadic.ofScaledInt coefficient 0) rounded; { value := rounded, status := { overflow := encodingStatus.overflow, inexact := !dyadicIsIntegral exact }, ternary := dyadicTernary exact rounded }

On finite input, roundToIntegral rounds the exact dyadic to an unbounded integer, then encodes that integer in the selected direction. The status records discarded fractional bits and the encoder's overflow classification, and the ternary value compares the delivered value with the input.

On a finite input of an IEEE format whose exponent range reaches the precision, the selected integer is represented exactly and reports no overflow. Fractional input can still set inexact. The range condition holds for IEEE 754's standard binary interchange formats.

Truncation toward zero cannot increase the magnitude of an exact dyadic.

Truncating a finite IEEE value toward zero is finite, for any exponent range.

Truncation toward zero computes floor or ceiling without an exponent-range restriction.

Truncation toward zero of a finite IEEE value never signals overflow.

Integral rounding of a finite IEEE value never overflows when fmt.fracWidth ≤ fmt.maxNormalExponent.

Integral rounding of a finite IEEE value is finite when the exponent range reaches the precision.

theorem FloatLib.Floats.Formats.BinaryInterchange.Model.toReal_roundToIntegral {fmt : FloatFormat} (hfmt : fmt.isIEEE = true) (hrange : ↑fmt.fracWidth ≤ fmt.maxNormalExponent) (value : Model fmt) (mode : IEEERoundingMode) (exact : Numerics.Dyadic) (hd : value.toDyadic? = some exact) :
toReal (value.roundToIntegral mode) = ↑(roundDyadicToInt mode exact)

The real value of a finite integral rounding is the integer selected by roundDyadicToInt.

theorem FloatLib.Floats.Formats.BinaryInterchange.Model.exists_int_toReal_roundToIntegral {fmt : FloatFormat} (hfmt : fmt.isIEEE = true) (hrange : ↑fmt.fracWidth ≤ fmt.maxNormalExponent) (value : Model fmt) (mode : IEEERoundingMode) (hfinite : value.isFinite = true) :
∃ (n : ℤ), toReal (value.roundToIntegral mode) = ↑n

The result of integral rounding is an integer.

Rounding toward negative infinity computes the floor of the real value.

Rounding toward positive infinity computes the ceiling of the real value.

Rounding toward zero truncates the real value: floor when nonnegative, ceiling otherwise.

Rounding to nearest with ties away from zero computes the nearest integer and resolves a tie toward the integer of larger magnitude, roundToIntegralTiesToAway of IEEE 754-2019. This is Flocq's nearestChoice nearestAwayChoice.

Rounding away from zero computes the ceiling of a nonnegative value and the floor of a negative one, as MPFR's mpfr_rint does under MPFR_RNDA.

Rounding to nearest computes the nearest integer with ties to even, nearestEven from the Flocq theory. Mathlib's round resolves ties toward positive infinity.