Robert Joseph George

When Rounding Breaks Machine Learning

A formalization of numerical accuracy across various machine learning libraries.

Authors

Affiliations

Published

Robert Joseph George

Sasha Rush

November 2026

The softmax bug that started it

A few weeks ago, Jon Barron shared a post about two numerical bugs in softmax and cross-entropy, based on work with Dan Gnanapragasam and Michael Tschannen. I went back to TorchLean and checked our own softmax implementation. Funny enough, it had the same problem: in float32, the target gradient became zero even though the true answer was nonzero and representable. We'd already proved the formula correct over the real numbers, but as Edward Yang pointed out, that didn't establish its floating-point accuracy. I wanted to know what else we were missing.

FloatLib lets us model the floating-point arithmetic directly and prove error or sign bounds for the formulas we execute. Blanchard and the Highams studied softmax and log-sum-exp in detail, and Prieto and collaborators had already identified Softmax Collapse. I wanted to bring that analysis into TorchLean, compare the library calls, and try different formulas where we found failures.

Now, the fundamental operators

After discussing softmax with Sasha, we decided to look at more of the fundamental operators : ) An operator is one of the building blocks of a neural network: addition, matrix multiplication, an activation, normalization, or a loss. These are the calls we combine when we build a model in PyTorch or JAX. The mathematical specification tells us what each operator should compute. The implementation also chooses the precision of intermediate values, the order of additions, and when to round. So the same operator can give different answers in different libraries, even with the same mathematical definition.

We examined all 154 TorchLean operators, or 162 entries when variants are counted separately. We have executable Lean rules for 159 entries; erf, erf-based GELU, and custom are not covered by that executable sweep. We compared the matching operations wherever available in PyTorch, JAX, TensorFlow, NumPy, CuPy, ONNX Runtime, and MLX, with CPU and GPU measurements kept separate. The main comparison spans several commonly used precisions and roughly 780 million outputs. Later, we take selected original and rewritten formulas through 526 different formats using FloatLib. The study combines executable Lean specifications, machine-checked proofs, and cross-library comparisons.1

Operator inventory 162 entries in 16 families
FamilyEntriesOperators and variants
Arithmetic18add, sub, mul, div, div floor, div trunc, addcmul, addcdiv, lerp, neg, abs, square, reciprocal, scale, fmod, remainder, copysign, nextafter
Roots and powers6sqrt, sqrt clampNeg, rsqrt, cbrt, pow, hypot
Rounding to integers6floor, ceil, round, trunc, frac, sign
Exponentials and logarithms7exp, exp2, expm1, log, log2, log10, log1p
Trigonometric and hyperbolic13sin, cos, tan, asin, acos, atan, atan2, sinh, cosh, tanh, asinh, acosh, atanh
Activations9relu, leakyReLU, elu, sigmoid, softplus, silu, gelu (tanh), gelu (erf), erf
Guarded operations6safeLog, safeInv, safeDiv, smoothAbs, nanToNum, clamp
Comparisons and selection14max, min, fmax, fmin, eq, ne, lt, le, gt, ge, isNaN, isInf, isFinite, select
Reductions, scans and sorting15reduce sum, reduce prod, reduce max, reduce min, mean, cumsum, cumprod, cummax, cummin, argmax, argmin, sort, sort desc, topk, topKMask
Softmax and losses14softmax, logSoftmax, maskedSoftmax, crossEntropy, crossEntropyProbs, binaryCrossEntropy, mseLoss, maeLoss, huberLoss, hingeLoss, poissonLoss, logCoshLoss, cosineLoss, distill
Layers13linear, matmul, scaledMatmul, contract, conv, convTranspose, pool, smoothMaxPool, layerNorm, batchNorm, batchNormRunning, embedding, dropout
Attention, scans and transforms6attention, attnFromScores, multiheadAttn, selectiveScan, rfft, irfft
Movement and indexing17detach, reshape, permute, broadcast, fullLike, flip, slice, pad, cat, gather, scatter, indexAt, indices, encodeIndex, decodeIndex, cast, bitcast
Logic, bits and integers14logicalNot, logicalAnd, logicalOr, logicalXor, bitwiseAnd, bitwiseOr, bitwiseXor, bitwiseNot, bitwiseLeftShift, shiftRightArith, shiftRightLogical, populationCount, countLeadZeros, mulhi
Random3randUniform, randn, bernoulliMask
No rule1custom

Preliminaries

In Lean Verified Precision, Sasha discussed why a formula that is right over the reals can still behave badly in floating point. Here, let's start with how we're measuring error. A floating-point format represents only certain numbers; the gap between two neighboring numbers at a given magnitude is one unit in the last place, or ULP. Immediately above 1 in float32:

\[ \begin{aligned} \text{next value}&=1+2^{-23}\\ &\approx1.0000001192,\\[3pt] \text{gap}&=2^{-23}\approx1.19\times10^{-7}. \end{aligned} \]

That spacing changes with the magnitude of the number, so a ULP is not a fixed tolerance. When I write zero ULPs in a table, I mean the result agrees with the exact mathematical answer rounded once to the chosen format; one ULP means the result is one representable step away. That reference rounds only at the end. A program can round after every intermediate operation. We also measure forward error, the difference between the value returned by the computation and the exact value of the function, either as an absolute difference or relative to the exact answer when it is nonzero. We use the same measurements for gradients. For more background, Higham's book is a good reference.

\[ \begin{aligned} \text{absolute error}&=|\widehat{y}-y|,\\[3pt] \text{relative error}&=\frac{|\widehat{y}-y|}{|y|}. \end{aligned} \]

Let's check the error in Lean. FloatLib's roundoff tactic analyzes a floating-point expression against its real-valued reference. It follows the arithmetic operations, applies their rounding theorems, and combines the contributions into an absolute or mixed error bound. The command roundoff mixed theorem ... using ... generates a reusable theorem and the finiteness and range conditions needed for its proof. Once the remaining goals are discharged, Lean's kernel checks the theorem.2

When we ran roundoff on our old softmax implementation, it flagged the problem in under a second. For logits [9, -9, -9], with class 0 as the target, the original float32 computation gives a target gradient of zero, while the real gradient is about \(-3.046\times10^{-8}\). We can run this float32 calculation in Lean and check its error against the exact gradient.

Download the complete Lean example (Lean 4.35.0).

Definitions and real-gradient proof
import FloatLib.Numerics.Enclosure.Elementary.Proof
import TorchLean.NN.Softmax.Correctness
import TorchLean.Verify.RuntimeApprox.Roundoff.CrossEntropy
import TorchLeanExamples.DeepDives.Floats.RoundingBugs

/-!
## Definitions and the exact real-valued gradient

Checked with Lean 4.35.0 and TorchLean revision bb95db148ab63e3beb3e9c43813ad782bdddad67.
Run `lake env lean /path/to/SoftmaxBlog.lean` from that TorchLean checkout.
-/

namespace TorchLean.Examples.BlogSoftmax

open Tensor
open FloatLib.Floats FloatLib.Numerics
open FloatLib.Floats.Formats.BinaryInterchange

section Formulas

variable {α : Type} [Storage α] [Context α]

/-- Logits `[m, -m, -m]`. The target class `0` leads the other two by `2 * m`. -/
def logits (m : α) : Tensor α [3] := Tensor.ofFn fun i => if i = 0 then m else -m

/-- The target entry of the standard log-softmax at `logits m`. -/
def standardLogProbability (m : α) : α :=
  (StandardSoftmax.logSoftmax 0 (logits m)).getScalar 0

/-- The standard cross-entropy of `logits m` against the target `0`. -/
def standardLoss (m : α) : α :=
  StandardSoftmax.crossEntropyLogits 0 (logits m) SoftmaxCrossEntropy.target

/-- The target entry of the standard cross-entropy gradient at `logits m`. -/
def standardGradient (m : α) : α :=
  (StandardSoftmax.crossEntropyLogitsDeriv 0 (logits m)
    SoftmaxCrossEntropy.target).getScalar 0

/-- The target entry of `Tensor.crossEntropyBackward .logits` at `logits m`. -/
def gradient (m : α) : α :=
  (Tensor.crossEntropyBackward .logits (logits m) SoftmaxCrossEntropy.target ⟨0,
      by exact Nat.zero_lt_succ _⟩).getScalar 0

end Formulas

/-- The softmax probability `2 exp (-gap) / (1 + 2 exp (-gap))` of the two classes of
`logits (gap / 2)` other than the target. -/
noncomputable def tailMass (gap : ℝ) : ℝ :=
  2 * Real.exp (-gap) / (1 + 2 * Real.exp (-gap))

/-- Over the reals, the target gradient at `logits m` is `-tailMass (2 * m)`. -/
theorem gradient_real (m : ℝ) : gradient m = -tailMass (2 * m) := by
  have connected := congrArg (fun value : Vec 3 => value 0)
    (Tensor.getScalarE_logSoftmaxBackward (logits m)
      (Tensor.map (fun x => -x) SoftmaxCrossEntropy.target))
  have coordinate : gradient m = -1 + Real.exp m / (Real.exp m + 2 * Real.exp (-m)) := by
    have hdenom : axisMeanDenom [3] ⟨0, Shape.AxisInBounds.proof⟩ = 1 := rfl
    simp only [gradient, Tensor.crossEntropyBackward, CrossEntropy.logProbs_real, reduceIte, hdenom]
    simp [Vec.logSoftmaxVJP, Vec.softmax, Vec.sumExp,
      Fin.sum_univ_three, logits, SoftmaxCrossEntropy.target] at connected ⊢
    rw [connected]
    ring
  have hexp : Real.exp (-(2 * m)) = Real.exp (-m) * Real.exp (-m) := by
    rw [← Real.exp_add]
    ring_nf
  have hinverse : Real.exp m * Real.exp (-m) = 1 := by
    rw [← Real.exp_add, add_neg_cancel, Real.exp_zero]
  rw [coordinate, tailMass, hexp]
  have hpositive : 0 < Real.exp (-m) := Real.exp_pos _
  field_simp
  nlinarith [hinverse]

end TorchLean.Examples.BlogSoftmax

An absolute error tolerance of \(10^{-7}\) would accept zero even though the target gradient has disappeared. So we check a mixed bound with relative allowance \(r\) and absolute allowance \(a\):

\[ |\widehat{y}-y|\le r|y|+a. \]

To exclude an incorrect zero, the allowed error must be smaller than the true gradient. Let \(u\) be unit roundoff and \(\eta\) the underflow allowance. At this input, we use:

\[ \begin{aligned} r&=32u,\qquad a=32\eta,\\ r|y|+a&\approx5.8\times10^{-14}. \end{aligned} \]

That bound rejects zero and accepts the replacement, whose measured error is about \(4.5\times10^{-16}\). The corresponding kernel checked statements are in RoundingBugs.lean.

Float32 counterexample and error bounds
/-! ## The binary32 counterexample and the replacement's error bound -/

namespace TorchLean.Examples.BlogSoftmax

open Tensor
open FloatLib.Floats FloatLib.Numerics
open FloatLib.Floats.Formats.BinaryInterchange

/-- Rational bounds `lo` and `hi` on the endpoints of FloatLib's enclosure of `exp (-gap)` bound
`tailMass gap` by `2 lo / (1 + 2 lo)` and `2 hi / (1 + 2 hi)`, so by any `a` below the
first and any `b` above the second. -/
private theorem tailMass_mem_Icc (gap degree : ℕ) (lo hi : ℚ) {a b : ℝ}
    (hlo₀ : 0 ≤ lo) (hlo : lo ≤ (Enclosure.exp (-gap) degree).lo)
    (hhi : (Enclosure.exp (-gap) degree).hi ≤ hi)
    (ha : a ≤ ((2 * lo / (1 + 2 * lo) : ℚ) : ℝ)) (hb : ((2 * hi / (1 + 2 * hi) : ℚ) : ℝ) ≤ b) :
    tailMass gap ∈ Set.Icc a b := by
  obtain ⟨lower, upper⟩ := Enclosure.contains_exp (-gap) degree
  have increasing {s t : ℝ} (hs : 0 ≤ s) (hst : s ≤ t) :
      2 * s / (1 + 2 * s) ≤ 2 * t / (1 + 2 * t) := by
    rw [div_le_div_iff₀ (by positivity) (by linarith)]
    nlinarith
  push_cast at lower upper ha hb ⊢
  exact ⟨ha.trans (increasing (by exact_mod_cast hlo₀) ((Rat.cast_le.mpr hlo).trans lower)),
    (increasing (Real.exp_pos _).le (upper.trans (Rat.cast_le.mpr hhi))).trans hb⟩

section Bounds

variable {format : FloatFormat} {plan : Configured.StoragePlan format} {code : Type}
    [ExecFloat.ModelCodec plan (Model format) code]

local notation "Value" =>
  ExecFloat.Binary format.expWidth format.fracWidth format.encoding format.exponentBias
    format.expWidth_ge_two format.fracWidth_pos format.exponentBias_pos
    format.exponentBias_le_maxFinite plan code

/-- A value that decodes to zero is not within 32 units of roundoff and underflow of `-c`, for
`c ∈ [lo, hi]` with `0 < lo`, when `32 (u hi + 2 ^ e)` is below `lo` for a power `2 ^ e` at least
the underflow allowance. -/
private theorem not_mixedError_of_eq_zero {x : Value} {c lo hi : ℝ} (e : ℤ)
    (hx : ExecFloat.Binary.toRat? x = some 0) (hc : c ∈ Set.Icc lo hi) (hlo₀ : 0 < lo)
    (he : FloatFormat.minSubnormalExponent format - 1 ≤ e)
    (hallowance : 32 * (Model.unitRoundoffAt format * hi + 2 ^ e) < lo) :
    ¬ MixedError (ExecFloat.Binary.toReal x) (-c) (32 * Model.unitRoundoffAt format)
      (32 * Model.underflowErrorAt format) := by
  rw [ExecFloat.Binary.toReal_of_toRat?_eq_some hx, Rat.cast_zero]
  intro bound
  obtain ⟨hlo, hhi⟩ := hc
  have hu := Model.unitRoundoffAt_pos format
  have hη := Model.underflowErrorAt_le_zpow format he
  have hscaled := mul_le_mul_of_nonneg_left hhi hu.le
  have hpositive : 0 < c := hlo₀.trans_le hlo
  have h := bound.bound
  rw [zero_sub, neg_neg, abs_neg, abs_of_pos hpositive] at h
  linarith

/-- A value that decodes to a negative `q` is finite, negative and within 32 units of roundoff
and underflow of `-c`, for `c ∈ [lo, hi]`, when `-32 u lo ≤ q + lo` and `q + hi ≤ 32 u lo`. -/
private theorem mixedError_of_eq_some {x : Value} {q : ℚ} {c lo hi : ℝ}
    (hx : ExecFloat.Binary.toRat? x = some q) (hq : q < 0) (hc : c ∈ Set.Icc lo hi)
    (hlower : -(32 * Model.unitRoundoffAt format * lo) ≤ q + lo)
    (hupper : q + hi ≤ 32 * Model.unitRoundoffAt format * lo) :
    ExecFloat.Binary.isFinite x = true ∧
      MixedError (ExecFloat.Binary.toReal x) (-c) (32 * Model.unitRoundoffAt format)
        (32 * Model.underflowErrorAt format) ∧
      ExecFloat.Binary.toReal x < 0 := by
  obtain ⟨hlo, hhi⟩ := hc
  have hu := Model.unitRoundoffAt_pos format
  have hscaled : 32 * Model.unitRoundoffAt format * lo ≤ 32 * Model.unitRoundoffAt format * |-c| :=
    mul_le_mul_of_nonneg_left (hlo.trans ((le_abs_self c).trans (abs_neg c).ge)) (by positivity)
  rw [ExecFloat.Binary.toReal_of_toRat?_eq_some hx]
  refine ⟨Model.Algebraic.isFinite_of_toRat?_eq_some hx,
    (MixedError.of_abs_sub_le_mul (by positivity) ?_).mono le_rfl
      (mul_nonneg (by norm_num) (Model.underflowErrorAt_pos format).le),
    by exact_mod_cast hq⟩
  rw [sub_neg_eq_add, abs_le]
  constructor <;> linarith

end Bounds

/-! ## Binary32

The paper's logits `[9, -9, -9]`. With a gap of `18`, `2 exp (-18)` is below the binary32 unit
roundoff `2^-24`. -/

/-- FloatLib's enclosure of `exp (-18)` gives `tailMass 18` to eight digits. -/
private theorem binary32_tailMass_mem_Icc :
    tailMass 18 ∈ Set.Icc (30459958 / 10 ^ 15) (30459959 / 10 ^ 15) :=
  tailMass_mem_Icc 18 30 (152299797 / 10 ^ 16) (152299798 / 10 ^ 16)
    (by norm_num) (by decide +kernel) (by decide +kernel) (by norm_num) (by norm_num)

/-- The standard formulas evaluated with the binary32 primitives return zero for the target
log-probability, the loss and the target gradient. -/
theorem binary32_standard_toRat? :
    ExecFloat.Binary.toRat? (standardLogProbability (9 : Binary32)) = some 0 ∧
      ExecFloat.Binary.toRat? (standardLoss (9 : Binary32)) = some 0 ∧
      ExecFloat.Binary.toRat? (standardGradient (9 : Binary32)) = some 0 := by
  decide +kernel

/-- The exact probability of the non-target classes lies between `3e-8` and `3.1e-8`. -/
theorem binary32_tailMass_mem_Ioo :
    tailMass 18 ∈ Set.Ioo (3 / 10 ^ 8) (31 / 10 ^ 9) := by
  obtain ⟨lower, upper⟩ := binary32_tailMass_mem_Icc
  exact ⟨lt_of_lt_of_le (by norm_num) lower, lt_of_le_of_lt upper (by norm_num)⟩

/-- An absolute tolerance of `1e-7` accepts the standard target gradient. -/
theorem binary32_abs_sub_lt :
    |ExecFloat.Binary.toReal (standardGradient (9 : Binary32)) - -tailMass 18| <
      1 / 10 ^ 7 := by
  obtain ⟨lower, upper⟩ := binary32_tailMass_mem_Ioo
  rw [ExecFloat.Binary.toReal_of_toRat?_eq_some binary32_standard_toRat?.2.2, Rat.cast_zero,
    zero_sub, neg_neg, abs_of_pos (by linarith)]
  linarith

/-- The mixed bound with 32 units of binary32 roundoff and underflow rejects the standard target
gradient. -/
theorem binary32_not_mixedError :
    ¬ MixedError (ExecFloat.Binary.toReal (standardGradient (9 : Binary32))) (-tailMass 18)
      (32 * Model.unitRoundoffAt FloatFormat.binary32)
      (32 * Model.underflowErrorAt FloatFormat.binary32) :=
  not_mixedError_of_eq_zero (-64) binary32_standard_toRat?.2.2
    binary32_tailMass_mem_Icc (by norm_num) (by decide)
    (by norm_num [Model.unitRoundoffAt_eq, FloatFormat.binary32])

/-- The target gradient `gradient 9` is finite, negative and within the mixed bound with 32
units of binary32 roundoff and underflow. -/
theorem binary32_mixedError :
    ExecFloat.Binary.isFinite (gradient (9 : Binary32)) = true ∧
      MixedError (ExecFloat.Binary.toReal (gradient (9 : Binary32))) (-tailMass 18)
        (32 * Model.unitRoundoffAt FloatFormat.binary32)
        (32 * Model.underflowErrorAt FloatFormat.binary32) ∧
      ExecFloat.Binary.toReal (gradient (9 : Binary32)) < 0 :=
  mixedError_of_eq_some (q := -2143429 / 2 ^ 46) (by decide +kernel) (by norm_num)
    binary32_tailMass_mem_Icc (by norm_num [Model.unitRoundoffAt_eq, FloatFormat.binary32])
    (by norm_num [Model.unitRoundoffAt_eq, FloatFormat.binary32])

end TorchLean.Examples.BlogSoftmax

FloatLib can also carry these bounds through expressions with variables, loops, and tensor sums. For the replacement, the generated bound at our input is about \(4.6\times10^{-14}\). We separately proved a sign theorem: when the target logit is maximal and at least one other class has a positive exponential contribution, the rewritten target gradient remains negative, for any class count and IEEE format under the stated assumptions.

Reference proof and roundoff theorem
/-! ## Generating an error bound for variable inputs -/

namespace TorchLean.Examples.BlogSoftmaxRoundoff

open Tensor
open FloatLib.Floats FloatLib.Numerics
open FloatLib.Floats.Formats.BinaryInterchange

variable {format : FloatFormat} {plan : Configured.StoragePlan format} {code : Type}
  [ExecFloat.ModelCodec plan (Model format) code]

local notation "Value" => ExecFloat (Configured.Family format code plan)

attribute [local roundoff_rule] TorchLean.Roundoff.CrossEntropy.log_probs_error

/-- The cross-entropy gradient's schedule on decoded logits `x`, with backward pivot `p'` and the
sum `S` of the exponentials `exp (x j)` folded in coordinate order, has the exact gradient
`softmax x i - [i = label]` as its reference: `exp (x j - log S)` is `softmax x j`, and at the
backward pivot the VJP's formula for the pivot entry has the same value. -/
theorem softmax_sub_oneHot_eq {n : Nat} (x : Fin (n + 1) → ℝ) (p' label i : Fin (n + 1)) :
    let S := (Tensor.Rep.coordinates [n + 1]).foldl (fun sum coordinate =>
      sum + Real.exp (x coordinate.1)) 0
    let q (j : Fin (n + 1)) : ℝ := Real.exp (x j - Real.log S)
    (if i = p' then
        -(q p' - 1) * -(if i = label then 1 else 0) - q p' * if label = p' then 0 else -1
      else q i - if i = label then 1 else 0) =
      Real.exp (x i) / ∑ j, Real.exp (x j) - if i = label then 1 else 0 := by
  intro S q
  have hS : S = ∑ j, Real.exp (x j) := Tensor.Rep.foldl_coordinates_add fun j => Real.exp (x j)
  have hq (j : Fin (n + 1)) : q j = Real.exp (x j) / ∑ k, Real.exp (x k) := by
    change Real.exp (x j - Real.log S) = _
    rw [Real.exp_sub, hS,
      Real.exp_log (Finset.sum_pos (fun _ _ => Real.exp_pos _) Finset.univ_nonempty)]
  simp only [hq]
  split_ifs <;> simp_all

/-- `softmax_sub_oneHot_eq` on the decoded logits of a vector: the reference `roundoff` infers for
the cross-entropy gradient is the exact gradient. -/
theorem gradient_reference [Storage Value] {n : Nat} (t : Tensor Value [n + 1])
    (label i : Fin (n + 1)) :
    let p' : Fin (n + 1) := Softmax.pivot (CrossEntropy.vectorLogProbs t)
    let x (j : Fin (n + 1)) : ℝ :=
      ExecFloat.Binary.toReal (Tensor.Rep.get t (j, PUnit.unit))
    let q (j : Fin (n + 1)) : ℝ := Real.exp (x j - Real.log
      ((Tensor.Rep.coordinates [n + 1]).foldl (fun sum coordinate =>
        sum + Real.exp (x coordinate.1)) 0))
    (if i = p' then
        -(q p' - 1) * -(if i = label then 1 else 0) - q p' * if label = p' then 0 else -1
      else q i - if i = label then 1 else 0) =
      Real.exp (ExecFloat.Binary.toReal (t.getScalar i)) /
          ∑ j, Real.exp (ExecFloat.Binary.toReal (t.getScalar j)) -
        if i = label then 1 else 0 := by
  intro p' x q
  simp only [Tensor.getScalar_eq_apply]
  exact softmax_sub_oneHot_eq x p' label i

roundoff mixed theorem gradient_error using gradient_reference :=
  fun [Storage Value] {n : Nat} (t : Tensor Value [n + 1]) (label : Fin (n + 1))
    (_hformat : format.isIEEE = true)
    (_hfinite : ∀ i, ExecFloat.Binary.isFinite (t.getScalar i) = true) (i : Fin (n + 1)) =>
    ExecFloat.Binary.toReal ((Tensor.crossEntropyBackward .logits t
      (Tensor.ofFn fun j => if j = label then 1 else 0)
      ⟨0, by exact Nat.zero_lt_succ _⟩).getScalar i)

end TorchLean.Examples.BlogSoftmaxRoundoff

Running the operators across precisions

Now let's look at what the operators actually returned across precisions and libraries. In the Lean sweep, 57,547 outputs (96.8%) agreed with the exact answer rounded once. Another 1,372 agreed with TorchLean's specified sequence of arithmetic steps, rather than a single final rounding. Intermediate rounding explains why those two references can give different answers. The figure puts Lean beside the seven numerical libraries and separates CPU from GPU wherever we have both. Each color records the largest error found among the tested inputs.

correctly rounded at every inputat most 1 ulp off2 to 16 ulps offmore than 16 ulps off somewhereonly the sign of a zero differsNaN or ∞ where the exact value is finite (or the reverse)differs only by a convention: limits at ±∞ or NaN, saturation, ties, a fully masked rowrandom: values recorded, no referencethe library rejects this dtypeno counterpartred outline: an IEEE 754 operation (add, subtract, multiply, divide, fma, square root, conversion) in an IEEE format (float64, float32, float16), where the standard requires the correctly rounded result
float64LeanPyTorch CPUPyTorch GPUJAX CPUJAX GPUTensorFlow CPUTensorFlow GPUNumPy CPUCuPy GPUONNX Runtime CPUONNX Runtime GPUMLX CPUfloat32LeanPyTorch CPUPyTorch GPUJAX CPUJAX GPUTensorFlow CPUTensorFlow GPUNumPy CPUCuPy GPUONNX Runtime CPUONNX Runtime GPUMLX CPUbfloat16LeanPyTorch CPUPyTorch GPUJAX CPUJAX GPUTensorFlow CPUTensorFlow GPUNumPy CPUCuPy GPUONNX Runtime CPUONNX Runtime GPUMLX CPUfloat16LeanPyTorch CPUPyTorch GPUJAX CPUJAX GPUTensorFlow CPUTensorFlow GPUNumPy CPUCuPy GPUONNX Runtime CPUONNX Runtime GPUMLX CPUfloat8 E5M2LeanPyTorch CPUPyTorch GPUJAX CPUJAX GPUTensorFlow CPUTensorFlow GPUNumPy CPUCuPy GPUONNX Runtime CPUONNX Runtime GPUMLX CPUfloat8 E4M3LeanPyTorch CPUPyTorch GPUJAX CPUJAX GPUTensorFlow CPUTensorFlow GPUNumPy CPUCuPy GPUONNX Runtime CPUONNX Runtime GPUMLX CPULean onlyTF32posit16
Arithmetic19 rows
add
sub
mul
div
div floor
div trunc
fma (IEEE line)
addcmul
addcdiv
lerp
neg
abs
square
reciprocal
scale
fmod
remainder
copysign
nextafter
Roots and powers6 rows
sqrt
sqrt clampNeg
rsqrt
cbrt
pow
hypot
Rounding to integers6 rows
floor
ceil
round
trunc
frac
sign
Exponentials and logarithms7 rows
exp
exp2
expm1
log
log2
log10
log1p
Trigonometric and hyperbolic13 rows
sin
cos
tan
asin
acos
atan
atan2
sinh
cosh
tanh
asinh
acosh
atanh
Activations9 rows
relu
leakyReLU
elu
sigmoid
softplus
silu
gelu (tanh)
gelu (erf)
erf
Guarded operations6 rows
safeLog
safeInv
safeDiv
smoothAbs
nanToNum
clamp
Comparisons and selection14 rows
max
min
fmax
fmin
eq
ne
lt
le
gt
ge
isNaN
isInf
isFinite
select
Reductions, scans and sorting15 rows
reduce sum
reduce prod
reduce max
reduce min
mean
cumsum
cumprod
cummax
cummin
argmax
argmin
sort
sort desc
topk
topKMask
Softmax and losses14 rows
softmax
logSoftmax
maskedSoftmax
crossEntropy
crossEntropyProbs
binaryCrossEntropy
mseLoss
maeLoss
huberLoss
hingeLoss
poissonLoss
logCoshLoss
cosineLoss
distill
Layers13 rows
linear
matmul
scaledMatmul
contract
conv
convTranspose
pool
smoothMaxPool
layerNorm
batchNorm
batchNormRunning
embedding
dropout
Attention, scans and transforms6 rows
attention
attnFromScores
multiheadAttn
selectiveScan
rfft
irfft
Movement and indexing17 rows
detach
reshape
permute
broadcast
fullLike
flip
slice
pad
cat
gather
scatter
indexAt
indices
encodeIndex
decodeIndex
cast
bitcast
Logic, bits and integers14 rows
logicalNot
logicalAnd
logicalOr
logicalXor
bitwiseAnd
bitwiseOr
bitwiseXor
bitwiseNot
bitwiseLeftShift
shiftRightArith
shiftRightLogical
populationCount
countLeadZeros
mulhi
Random3 rows
randUniform
randn
bernoulliMask
No rule1 row
custom
Figure 1. Numerical accuracy across the operator catalogue.Each cell summarizes one operator, format, and implementation over the tested inputs. Blue shades distinguish correctly rounded results from increasing errors in ulps; red marks a mismatch involving NaN or infinity. Signed-zero and other conventions have separate labels. The CPU and GPU results are separate measurements, not estimates of failure rates during training.
Arithmetic and reference values

Library references use MPFR; Lean references use exact rationals and high-precision mpmath. Each reference is rounded once to the destination format. The red outline marks an IEEE operation in an IEEE format for which correct rounding is required. Missing counterparts and unsupported dtypes are not counted as successful tests.

Table: every cell as text

✓ correctly rounded at every input; a number is the worst error in ulps; ±0 only the sign of a zero differs; NaN/∞ a NaN or infinity where the exact value is finite (or the reverse); rejects: the library refuses the dtype; · not run or no counterpart.

familyoperatorformatLeanPyTorch CPUPyTorch GPUJAX CPUJAX GPUTensorFlow CPUTensorFlow GPUNumPy CPUCuPy GPUONNX Runtime CPUONNX Runtime GPUMLX CPU
Arithmeticaddfloat64✓✓✓9,007,199,254,740,990✓9,007,199,254,740,990✓✓✓✓✓✓
Arithmeticaddfloat32✓✓✓16,777,214✓16,777,21416,777,214✓16,777,214✓✓✓
Arithmeticaddbfloat16✓✓✓254✓254254✓254rejects✓✓
Arithmeticaddfloat16✓✓✓✓✓✓✓✓✓✓✓✓
Arithmeticaddfloat8 E5M2✓✓✓✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Arithmeticaddfloat8 E4M3✓convconv✓✓rejectsrejects✓rejectsrejectsrejectsrejects
ArithmeticaddTF32✓
Arithmeticaddposit16✓
Arithmeticsubfloat64✓✓✓4,503,599,627,370,495✓4,503,599,627,370,495✓✓✓✓✓✓
Arithmeticsubfloat32✓✓✓8,582,326✓8,582,3268,582,326✓8,582,326✓✓✓
Arithmeticsubbfloat16✓✓✓176✓176176✓176rejects✓✓
Arithmeticsubfloat16✓✓✓✓✓✓✓✓✓✓✓✓
Arithmeticsubfloat8 E5M2✓✓✓✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Arithmeticsubfloat8 E4M3✓convconv✓✓rejectsrejects✓rejectsrejectsrejectsrejects
ArithmeticsubTF32✓
Arithmeticsubposit16✓
Arithmeticmulfloat64✓✓✓4,598,966,579,610,778,593✓4,598,966,579,610,778,593✓✓✓✓✓✓
Arithmeticmulfloat32✓✓✓1,082,130,429✓1,082,130,4291,082,130,429✓1,082,130,429✓✓✓
Arithmeticmulbfloat16✓✓✓16,509✓16,50916,509✓16,509rejects✓✓
Arithmeticmulfloat16✓✓✓✓✓✓✓✓✓✓✓✓
Arithmeticmulfloat8 E5M2✓✓✓✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Arithmeticmulfloat8 E4M3✓convconv✓✓rejectsrejects✓rejectsrejectsrejectsrejects
ArithmeticmulTF32✓
Arithmeticmulposit16✓
Arithmeticdivfloat64✓✓✓NaN/∞✓NaN/∞✓✓✓✓✓✓
Arithmeticdivfloat32✓✓✓NaN/∞2NaN/∞NaN/∞✓NaN/∞✓✓✓
Arithmeticdivbfloat16✓✓✓NaN/∞✓NaN/∞NaN/∞✓NaN/∞rejects✓✓
Arithmeticdivfloat16✓✓✓✓≤1✓✓✓✓✓✓✓
Arithmeticdivfloat8 E5M2✓✓✓✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Arithmeticdivfloat8 E4M3✓convconv✓✓rejectsrejects✓rejectsrejectsrejectsrejects
ArithmeticdivTF32✓
Arithmeticdivposit16✓
Arithmeticdiv floorfloat64✓22NaN/∞2NaN/∞4,607,182,418,800,017,40824,607,182,418,800,017,4084,607,182,418,800,017,4084,607,182,418,800,017,4084,607,182,418,800,017,408
Arithmeticdiv floorfloat32≤122NaN/∞4NaN/∞NaN/∞2NaN/∞1,065,353,2161,065,353,2161,065,353,216
Arithmeticdiv floorbfloat16✓2convNaN/∞2NaN/∞NaN/∞convNaN/∞rejectsrejects16,256
Arithmeticdiv floorfloat16≤1NaN/∞NaN/∞NaN/∞NaN/∞15,36015,360NaN/∞15,36015,36015,36015,360
Arithmeticdiv floorfloat8 E5M2≤1NaN/∞NaN/∞NaN/∞NaN/∞rejectsrejectsNaN/∞rejectsrejectsrejectsrejects
Arithmeticdiv floorfloat8 E4M3≤1convconv22rejectsrejects✓rejectsrejectsrejectsrejects
Arithmeticdiv floorTF32≤1
Arithmeticdiv truncfloat64✓2,251,799,813,685,2482,251,799,813,685,248NaN/∞2,251,799,813,685,248NaN/∞2,251,799,813,685,248·2,251,799,813,685,2482,251,799,813,685,2482,251,799,813,685,248rejects
Arithmeticdiv truncfloat32≤14,194,3044,194,304NaN/∞1,065,353,216NaN/∞NaN/∞·NaN/∞4,194,3044,194,304rejects
Arithmeticdiv truncbfloat16✓6464NaN/∞16,256NaN/∞NaN/∞·NaN/∞rejectsrejectsrejects
Arithmeticdiv truncfloat16≤1512512512512512512·512±0512rejects
Arithmeticdiv truncfloat8 E5M22✓✓260rejectsrejects·rejectsrejectsrejectsrejects
Arithmeticdiv truncfloat8 E4M3≤1convconv456rejectsrejects·rejectsrejectsrejectsrejects
Arithmeticdiv truncTF32≤1
Arithmeticfma (IEEE line)float64·✓✓4,798,521,906,915,898,2891,989,962,520,682···✓rejectsrejectsrejects
Arithmeticfma (IEEE line)float32·✓✓1,743,574,162919,753,968···1,743,574,162rejectsrejectsrejects
Arithmeticfma (IEEE line)bfloat16·≤1≤130,907≤1···rejectsrejectsrejectsrejects
Arithmeticfma (IEEE line)float16·≤1≤1NaN/∞NaN/∞···rejectsrejectsrejectsrejects
Arithmeticfma (IEEE line)float8 E5M2·NaN/∞NaN/∞NaN/∞NaN/∞···rejectsrejectsrejectsrejects
Arithmeticfma (IEEE line)float8 E4M3·convconvNaN/∞≤1···rejectsrejectsrejectsrejects
Arithmeticaddcmulfloat64≤1✓✓4,865,530,273,319,972,4872,648,791,123,0704,865,530,273,319,972,4872,648,791,123,0702,648,791,123,0702,648,791,123,0702,648,791,123,0702,648,791,123,0702,648,791,123,070
Arithmeticaddcmulfloat32≤1✓✓2,055,270,886NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞
Arithmeticaddcmulbfloat16≤1≤1≤129,559≤129,55929,55923,84029,559rejects23,84023,840
Arithmeticaddcmulfloat16NaN/∞≤1≤1NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞≤1NaN/∞NaN/∞
Arithmeticaddcmulfloat8 E5M2≤1NaN/∞NaN/∞NaN/∞NaN/∞✓✓NaN/∞rejects≤1≤1rejects
Arithmeticaddcmulfloat8 E4M3≤1convconvNaN/∞≤1✓✓NaN/∞rejectsconvconvrejects
ArithmeticaddcmulTF32≤1
Arithmeticaddcdivfloat6433,547,485,734,6863,547,485,734,686NaN/∞3,547,485,734,686NaN/∞3,547,485,734,6863,547,485,734,6863,547,485,734,6863,547,485,734,6863,547,485,734,6863,547,485,734,686
Arithmeticaddcdivfloat32≤1970,800,625970,800,625NaN/∞970,800,625NaN/∞NaN/∞970,800,625NaN/∞970,800,625970,800,625970,800,625
Arithmeticaddcdivbfloat16≤1≤1≤1NaN/∞14,720NaN/∞NaN/∞26,186NaN/∞rejects26,18626,186
Arithmeticaddcdivfloat16NaN/∞88NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞8NaN/∞NaN/∞
Arithmeticaddcdivfloat8 E5M2≤1convconvNaN/∞NaN/∞✓✓NaN/∞rejects≤1≤1rejects
Arithmeticaddcdivfloat8 E4M3≤1convconvNaN/∞≤1✓✓NaN/∞rejectsconvconvrejects
ArithmeticaddcdivTF32≤1
Arithmeticlerpfloat6432,0482,0484,682,947,832,717,916,9092,5994,682,947,832,717,916,90917,69817,6982,5992,5992,5992,599
Arithmeticlerpfloat3234,278,190,0794,278,190,0791,673,840,181NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞
Arithmeticlerpbfloat163NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞3rejects3NaN/∞
Arithmeticlerpfloat16NaN/∞≤1≤1NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞≤1NaN/∞NaN/∞
Arithmeticlerpfloat8 E5M2NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞✓✓NaN/∞rejects≤1≤1rejects
Arithmeticlerpfloat8 E4M33convconvNaN/∞3✓✓NaN/∞rejects✓✓rejects
ArithmeticlerpTF323
Arithmeticnegfloat64✓✓✓✓✓✓✓✓✓✓✓✓
Arithmeticnegfloat32✓✓✓✓✓✓8,388,607✓8,388,607✓✓✓
Arithmeticnegbfloat16✓✓✓✓✓✓✓✓127rejects✓✓
Arithmeticnegfloat16✓✓✓✓✓✓✓✓✓✓✓✓
Arithmeticnegfloat8 E5M2✓✓✓✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Arithmeticnegfloat8 E4M3✓✓✓✓✓rejectsrejects✓rejectsrejectsrejectsrejects
ArithmeticnegTF32✓
Arithmeticnegposit16✓
Arithmeticabsfloat64✓✓✓✓✓✓✓✓✓✓✓✓
Arithmeticabsfloat32✓✓✓✓✓✓8,388,607✓8,388,607✓✓✓
Arithmeticabsbfloat16✓✓✓✓✓✓✓✓127rejects✓✓
Arithmeticabsfloat16✓✓✓✓✓✓✓✓✓✓✓✓
Arithmeticabsfloat8 E5M2✓±0✓✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Arithmeticabsfloat8 E4M3✓±0✓✓✓rejectsrejects✓rejectsrejectsrejectsrejects
ArithmeticabsTF32✓
Arithmeticabsposit16✓
Arithmeticsquarefloat64✓✓✓4,502,387,152,236,452✓4,502,387,152,236,452✓✓✓✓✓✓
Arithmeticsquarefloat32✓✓✓8,271,479✓8,271,4798,271,479✓8,271,479✓✓✓
Arithmeticsquarebfloat16✓✓✓127✓127127✓127rejects✓✓
Arithmeticsquarefloat16✓✓✓✓✓✓✓✓✓✓✓✓
Arithmeticsquarefloat8 E5M2✓✓✓✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Arithmeticsquarefloat8 E4M3✓convconv✓✓rejectsrejects✓rejectsrejectsrejectsrejects
ArithmeticsquareTF32✓
Arithmeticsquareposit16✓
Arithmeticreciprocalfloat64✓✓✓NaN/∞✓NaN/∞✓✓✓✓✓✓
Arithmeticreciprocalfloat32✓✓✓NaN/∞≤1NaN/∞NaN/∞✓NaN/∞✓✓✓
Arithmeticreciprocalbfloat16✓✓✓NaN/∞✓NaN/∞NaN/∞✓NaN/∞rejectsrejects✓
Arithmeticreciprocalfloat16✓✓✓✓✓✓✓✓✓✓✓✓
Arithmeticreciprocalfloat8 E5M2✓✓✓✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Arithmeticreciprocalfloat8 E4M3✓convconv✓✓rejectsrejects✓rejectsrejectsrejectsrejects
ArithmeticreciprocalTF32✓
Arithmeticreciprocalposit16✓
Arithmeticscalefloat64✓✓✓4,469,646,987,026,863✓4,469,646,987,026,863✓✓✓✓✓✓
Arithmeticscalefloat32✓✓✓8,366,804✓8,366,8048,366,804✓8,366,804✓✓✓
Arithmeticscalebfloat16✓✓✓127✓127127✓127rejects✓✓
Arithmeticscalefloat16✓✓✓✓✓✓✓✓✓✓✓✓
Arithmeticscalefloat8 E5M2✓✓✓✓✓✓✓✓rejects≤1≤1rejects
Arithmeticscalefloat8 E4M3✓convconv✓✓✓✓✓rejectsconvconvrejects
ArithmeticscaleTF32✓
Arithmeticscaleposit16✓
Arithmeticfmodfloat64✓NaN/∞✓NaN/∞✓NaN/∞NaN/∞✓✓✓✓rejects
Arithmeticfmodfloat32✓NaN/∞✓NaN/∞✓NaN/∞NaN/∞✓NaN/∞✓✓rejects
Arithmeticfmodbfloat16✓NaN/∞✓NaN/∞✓rejectsrejects✓NaN/∞rejects✓rejects
Arithmeticfmodfloat16✓✓✓✓✓rejectsrejects✓✓✓✓rejects
Arithmeticfmodfloat8 E5M2✓✓✓✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Arithmeticfmodfloat8 E4M3✓✓✓✓✓rejectsrejects✓rejectsrejectsrejectsrejects
ArithmeticfmodTF32✓
Arithmeticremainderfloat64±0NaN/∞±0NaN/∞±0NaN/∞±0✓NaN/∞rejectsrejects±0
Arithmeticremainderfloat32±0NaN/∞±0NaN/∞±0NaN/∞NaN/∞✓NaN/∞rejectsrejects±0
Arithmeticremainderbfloat16±0NaN/∞±0NaN/∞±0NaN/∞NaN/∞✓NaN/∞rejectsrejects65,279
Arithmeticremainderfloat16±0±0±0±0±0±0±0✓NaN/∞rejectsrejectsNaN/∞
Arithmeticremainderfloat8 E5M2±0±0±0±0±0rejectsrejects✓rejectsrejectsrejectsrejects
Arithmeticremainderfloat8 E4M3±0±0±0±0±0rejectsrejects✓rejectsrejectsrejectsrejects
ArithmeticremainderTF32±0
Arithmeticcopysignfloat64✓✓✓✓✓··✓✓rejectsrejectsrejects
Arithmeticcopysignfloat32✓✓✓✓✓··✓✓rejectsrejectsrejects
Arithmeticcopysignbfloat16✓✓✓✓✓··✓✓rejectsrejectsrejects
Arithmeticcopysignfloat16✓✓✓✓✓··✓✓rejectsrejectsrejects
Arithmeticcopysignfloat8 E5M2✓✓✓rejectsrejects··✓rejectsrejectsrejectsrejects
Arithmeticcopysignfloat8 E4M3✓✓✓rejectsrejects··✓rejectsrejectsrejectsrejects
ArithmeticcopysignTF32✓
Arithmeticnextafterfloat64✓✓✓8,279,395,750,864,635✓8,279,395,750,864,635✓✓✓rejectsrejectsrejects
Arithmeticnextafterfloat32✓✓✓16,758,093✓16,758,09316,758,093✓16,777,214rejectsrejectsrejects
Arithmeticnextafterbfloat16✓✓✓253✓rejectsrejects✓127rejectsrejectsrejects
Arithmeticnextafterfloat16✓✓✓✓✓rejectsrejects✓NaN/∞rejectsrejectsrejects
Arithmeticnextafterfloat8 E5M2✓NaN/∞NaN/∞✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Arithmeticnextafterfloat8 E4M3✓≤1≤1✓✓rejectsrejects✓rejectsrejectsrejectsrejects
ArithmeticnextafterTF32✓
Roots and powerssqrtfloat64✓≤1✓2,305,843,009,213,693,951✓2,305,843,009,213,693,951✓✓✓✓✓✓
Roots and powerssqrtfloat32✓≤1✓536,870,911≤1536,870,911536,870,911✓536,870,911✓✓✓
Roots and powerssqrtbfloat16✓✓✓NaN/∞✓NaN/∞NaN/∞✓NaN/∞rejects✓✓
Roots and powerssqrtfloat16✓✓✓✓✓✓✓✓✓✓✓✓
Roots and powerssqrtfloat8 E5M2✓✓✓✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Roots and powerssqrtfloat8 E4M3✓✓✓✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Roots and powerssqrtTF32✓
Roots and powerssqrtposit16✓
Roots and powerssqrt clampNegfloat64✓≤1✓2,305,843,009,213,693,951✓2,305,843,009,213,693,951✓✓✓✓✓✓
Roots and powerssqrt clampNegfloat32✓≤1✓536,870,911≤1536,870,911536,870,911✓536,870,911✓✓✓
Roots and powerssqrt clampNegbfloat16✓±0✓8,191✓8,1918,191✓8,191rejects✓✓
Roots and powerssqrt clampNegfloat16✓±0✓✓✓±0✓±0✓±0✓✓
Roots and powerssqrt clampNegfloat8 E5M2±0±0✓✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Roots and powerssqrt clampNegfloat8 E4M3±0±0✓✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Roots and powerssqrt clampNegTF32✓
Roots and powersrsqrtfloat64≤1≤1≤1NaN/∞≤1NaN/∞≤1≤1≤1≤1≤1≤1
Roots and powersrsqrtfloat32≤1≤1≤1NaN/∞≤1NaN/∞NaN/∞≤1NaN/∞≤1≤1≤1
Roots and powersrsqrtbfloat16≤1≤1✓NaN/∞✓NaN/∞NaN/∞≤1rejectsrejectsrejects≤1
Roots and powersrsqrtfloat16≤1≤1✓✓✓≤1✓≤1✓✓≤1≤1
Roots and powersrsqrtfloat8 E5M2≤1✓✓✓✓rejectsrejects≤1rejectsrejectsrejectsrejects
Roots and powersrsqrtfloat8 E4M3≤1convconv✓✓rejectsrejects≤1rejectsrejectsrejectsrejects
Roots and powersrsqrtTF32≤1
Roots and powersrsqrtposit16✓
Roots and powerscbrtfloat64✓··3,072,625,526,210,130,570✓3,072,625,526,210,130,570119≤1✓rejectsrejectsrejects
Roots and powerscbrtfloat32✓··1,352,746,263≤1713,031,679713,031,6792713,031,679rejectsrejectsrejects
Roots and powerscbrtbfloat16✓··20,640✓rejectsrejects✓10,879rejectsrejectsrejects
Roots and powerscbrtfloat16✓··≤1≤133✓≤1rejectsrejectsrejects
Roots and powerscbrtfloat8 E5M2✓··✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Roots and powerscbrtfloat8 E4M3✓··✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Roots and powerscbrtTF32✓
Roots and powerscbrtposit16✓
Roots and powerspowfloat64✓≤1≤1201,622,187,196,946,263≤1NaN/∞≤1≤1≤1≤1≤1≤1
Roots and powerspowfloat32✓≤1≤1NaN/∞≤1NaN/∞NaN/∞≤1NaN/∞≤1≤1≤1
Roots and powerspowbfloat16✓≤1≤1NaN/∞≤1NaN/∞NaN/∞≤1NaN/∞rejects≤1≤1
Roots and powerspowfloat16✓≤1≤1≤1≤1≤1≤1≤1≤1≤1≤1≤1
Roots and powerspowfloat8 E5M2✓✓✓≤1≤1rejectsrejects✓rejectsrejectsrejectsrejects
Roots and powerspowfloat8 E4M3✓convconv≤1≤1rejectsrejects✓rejectsrejectsrejectsrejects
Roots and powerspowTF32✓
Roots and powershypotfloat64✓≤126,369,051,672,525,771≤1NaN/∞NaN/∞≤12rejectsrejectsrejects
Roots and powershypotfloat32✓≤1≤111,863,282≤1NaN/∞NaN/∞✓11,863,282rejectsrejectsrejects
Roots and powershypotbfloat16✓✓✓NaN/∞✓rejectsrejects✓180rejectsrejectsrejects
Roots and powershypotfloat16✓≤1≤1NaN/∞NaN/∞NaN/∞NaN/∞≤1≤1rejectsrejectsrejects
Roots and powershypotfloat8 E5M2✓✓✓NaN/∞✓rejectsrejects✓rejectsrejectsrejectsrejects
Roots and powershypotfloat8 E4M3✓convconvNaN/∞✓rejectsrejects✓rejectsrejectsrejectsrejects
Roots and powershypotTF32✓
Roots and powershypotposit16✓
Rounding to integersfloorfloat64✓✓✓4,607,182,418,800,017,408✓4,607,182,418,800,017,408✓✓✓✓✓✓
Rounding to integersfloorfloat32✓✓✓1,065,353,216✓1,065,353,2161,065,353,216✓1,065,353,216✓✓✓
Rounding to integersfloorbfloat16✓✓✓16,256✓16,25616,256✓16,256rejectsrejects✓
Rounding to integersfloorfloat16✓✓✓✓✓✓✓✓✓✓✓✓
Rounding to integersfloorfloat8 E5M2✓✓✓✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Rounding to integersfloorfloat8 E4M3✓✓✓✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Rounding to integersfloorTF32✓
Rounding to integersfloorposit16✓
Rounding to integersceilfloat64✓✓✓4,607,182,418,800,017,408✓4,607,182,418,800,017,408✓✓✓✓✓✓
Rounding to integersceilfloat32✓✓✓1,065,353,216✓1,065,353,2161,065,353,216✓1,065,353,216✓✓✓
Rounding to integersceilbfloat16✓✓✓16,256✓16,25616,256✓16,256rejectsrejects✓
Rounding to integersceilfloat16✓✓✓✓✓✓✓✓✓✓✓✓
Rounding to integersceilfloat8 E5M2✓✓✓✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Rounding to integersceilfloat8 E4M3✓✓✓✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Rounding to integersceilTF32✓
Rounding to integersceilposit16✓
Rounding to integersroundfloat64✓✓✓✓✓✓±0✓✓✓✓✓
Rounding to integersroundfloat32✓✓✓✓✓✓±0✓✓✓✓✓
Rounding to integersroundbfloat16✓✓✓✓✓✓✓✓✓rejectsrejects✓
Rounding to integersroundfloat16✓✓✓✓✓✓±0✓✓✓✓✓
Rounding to integersroundfloat8 E5M2✓✓✓✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Rounding to integersroundfloat8 E4M3✓✓✓✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Rounding to integersroundTF32✓
Rounding to integersroundposit16✓
Rounding to integerstruncfloat64✓✓✓✓✓✓✓✓✓±0✓rejects
Rounding to integerstruncfloat32✓✓✓✓✓✓✓✓✓±0✓rejects
Rounding to integerstruncbfloat16✓✓✓✓✓rejectsrejects✓✓rejectsrejectsrejects
Rounding to integerstruncfloat16✓✓✓✓✓✓✓✓✓±0✓rejects
Rounding to integerstruncfloat8 E5M2✓✓✓✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Rounding to integerstruncfloat8 E4M3✓✓✓✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Rounding to integerstruncTF32✓
Rounding to integersfracfloat64✓✓✓4,503,599,627,370,495✓4,503,599,627,370,495✓convconv±0±0rejects
Rounding to integersfracfloat32✓✓✓8,388,607✓8,388,6078,388,607conv8,388,607±0±0rejects
Rounding to integersfracbfloat16✓✓✓127✓rejectsrejectsconv127rejects±0rejects
Rounding to integersfracfloat16✓✓✓✓✓✓✓NaN/∞NaN/∞±0±0rejects
Rounding to integersfracfloat8 E5M2✓✓✓✓✓rejectsrejectsNaN/∞rejectsrejectsrejectsrejects
Rounding to integersfracfloat8 E4M3✓✓✓✓✓rejectsrejects±0rejectsrejectsrejectsrejects
Rounding to integersfracTF32✓
Rounding to integerssignfloat64✓convconv4,607,182,418,800,017,408✓4,611,685,723,220,863,488✓±0±0±0convconv
Rounding to integerssignfloat32✓convconv1,065,353,216✓1,073,741,5181,065,353,216±01,065,353,216±0convconv
Rounding to integerssignbfloat16✓convconv16,256✓16,38316,256✓16,256convconvconv
Rounding to integerssignfloat16✓NaN/∞NaN/∞✓✓±0✓±0±0NaN/∞NaN/∞NaN/∞
Rounding to integerssignfloat8 E5M2✓NaN/∞NaN/∞✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Rounding to integerssignfloat8 E4M3✓convconv✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Rounding to integerssignTF32✓
Rounding to integerssignposit16✓
Exponentials and logarithmsexpfloat64✓≤1≤14,492,676,999,583,826≤14,492,676,999,583,826≤1≤1≤1≤1≤1NaN/∞
Exponentials and logarithmsexpfloat32✓≤128,386,47028,386,4708,386,47028,386,470≤12NaN/∞
Exponentials and logarithmsexpbfloat16✓✓✓109≤1109109✓109rejects✓NaN/∞
Exponentials and logarithmsexpfloat16✓≤1≤1≤1≤1≤1≤1≤1≤1≤1≤1≤1
Exponentials and logarithmsexpfloat8 E5M2✓✓✓≤1≤1rejectsrejects✓rejectsrejectsrejectsrejects
Exponentials and logarithmsexpfloat8 E4M3✓convconv✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Exponentials and logarithmsexpTF32✓
Exponentials and logarithmsexpposit16✓
Exponentials and logarithmsexp2float64✓≤1≤14,501,466,744,494,1787234,501,466,744,494,178≤1≤1≤1≤1≤1rejects
Exponentials and logarithmsexp2float32✓≤128,385,947688,385,9478,385,94738,385,947≤1≤1rejects
Exponentials and logarithmsexp2bfloat16✓✓✓NaN/∞NaN/∞rejectsrejects✓91rejects✓rejects
Exponentials and logarithmsexp2float16✓≤1≤11414≤1≤1≤1≤1≤1≤1rejects
Exponentials and logarithmsexp2float8 E5M2✓✓✓74rejectsrejects✓rejectsrejectsrejectsrejects
Exponentials and logarithmsexp2float8 E4M3✓convconv2≤1rejectsrejects✓rejectsrejectsrejectsrejects
Exponentials and logarithmsexp2TF32✓
Exponentials and logarithmsexpm1float64✓≤1≤1≤1≤13≤1≤1≤14,368,491,279,861,963,9394,368,491,279,861,963,939≤1
Exponentials and logarithmsexpm1float32✓≤1≤1≤1≤138,388,60738,388,607864,026,624867,266,040≤1
Exponentials and logarithmsexpm1bfloat16✓✓✓✓✓✓127✓127rejects15,231✓
Exponentials and logarithmsexpm1float16✓≤1≤1≤1≤1≤1≤1≤1≤1≤14,095≤1
Exponentials and logarithmsexpm1float8 E5M2✓✓✓✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Exponentials and logarithmsexpm1float8 E4M3≤1convconv✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Exponentials and logarithmsexpm1TF32✓
Exponentials and logarithmsexpm1posit16✓
Exponentials and logarithmslogfloat64✓≤1≤1NaN/∞≤1NaN/∞≤1≤1≤1≤1≤1≤1
Exponentials and logarithmslogfloat32✓≤1≤1NaN/∞≤1NaN/∞NaN/∞3NaN/∞3≤1≤1
Exponentials and logarithmslogbfloat16✓✓✓NaN/∞✓NaN/∞NaN/∞✓NaN/∞rejectsrejects✓
Exponentials and logarithmslogfloat16✓≤1≤1≤1≤1≤1≤1≤1≤1≤1≤1≤1
Exponentials and logarithmslogfloat8 E5M2✓✓✓✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Exponentials and logarithmslogfloat8 E4M3✓convconv✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Exponentials and logarithmslogTF32✓
Exponentials and logarithmslogposit16✓
Exponentials and logarithmslog2float64✓≤1≤1NaN/∞≤1NaN/∞2≤1≤122≤1
Exponentials and logarithmslog2float32✓≤1≤1NaN/∞≤1NaN/∞NaN/∞2NaN/∞3≤1≤1
Exponentials and logarithmslog2bfloat16✓✓✓NaN/∞2rejectsrejects✓NaN/∞rejectsrejects✓
Exponentials and logarithmslog2float16✓✓✓2222✓✓≤12✓
Exponentials and logarithmslog2float8 E5M2✓✓✓2≤1rejectsrejects✓rejectsrejectsrejectsrejects
Exponentials and logarithmslog2float8 E4M3✓convconv2≤1rejectsrejects✓rejectsrejectsrejectsrejects
Exponentials and logarithmslog2TF32✓
Exponentials and logarithmslog2posit16✓
Exponentials and logarithmslog10float64✓≤1≤1NaN/∞2NaN/∞2≤1≤1322
Exponentials and logarithmslog10float32✓≤12NaN/∞2NaN/∞NaN/∞2NaN/∞422
Exponentials and logarithmslog10bfloat16✓✓✓NaN/∞2rejectsrejects✓NaN/∞rejectsrejects✓
Exponentials and logarithmslog10float16✓≤1≤1≤1≤1≤1≤1≤1≤1≤1≤1≤1
Exponentials and logarithmslog10float8 E5M2✓✓✓≤1≤1rejectsrejects✓rejectsrejectsrejectsrejects
Exponentials and logarithmslog10float8 E4M3✓convconv≤1≤1rejectsrejects✓rejectsrejectsrejectsrejects
Exponentials and logarithmslog10TF32✓
Exponentials and logarithmslog10posit16✓
Exponentials and logarithmslog1pfloat64✓≤1≤14,503,599,627,370,495≤14,503,599,627,370,495≤1≤1≤14,368,491,427,922,774,0114,368,491,427,922,774,011≤1
Exponentials and logarithmslog1pfloat32✓≤1≤18,388,607≤18,388,6078,388,60728,388,607864,026,624864,026,624≤1
Exponentials and logarithmslog1pbfloat16✓✓✓127✓127127✓127rejectsrejects✓
Exponentials and logarithmslog1pfloat16✓≤1≤1≤1≤1≤1≤1≤1≤1≤14,096≤1
Exponentials and logarithmslog1pfloat8 E5M2✓✓✓≤1≤1rejectsrejects✓rejectsrejectsrejectsrejects
Exponentials and logarithmslog1pfloat8 E4M3≤1convconv✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Exponentials and logarithmslog1pTF32✓
Exponentials and logarithmslog1pposit16✓
Trigonometric and hyperbolicsinfloat64✓≤1≤1≤1≤1≤1≤1≤1≤14,368,955,796,522,032,135≤19,195,615,027,676,118,220
Trigonometric and hyperbolicsinfloat32✓≤1≤1≤1≤18,388,6078,388,607≤18,388,6072≤11,081,763,405
Trigonometric and hyperbolicsinbfloat16✓✓✓✓✓127127✓127rejects✓NaN/∞
Trigonometric and hyperbolicsinfloat16✓≤1≤1≤1≤1≤1≤1≤1≤1≤1✓≤1
Trigonometric and hyperbolicsinfloat8 E5M2✓✓✓✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Trigonometric and hyperbolicsinfloat8 E4M3✓✓✓✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Trigonometric and hyperbolicsinTF32✓
Trigonometric and hyperbolicsinposit16✓
Trigonometric and hyperboliccosfloat64✓≤1≤1≤1≤1≤1≤1≤1≤1650,613≤19,195,398,567,459,499,637
Trigonometric and hyperboliccosfloat32✓≤1≤1≤1≤12≤1≤1≤12≤12,432
Trigonometric and hyperboliccosbfloat16✓✓✓✓✓✓✓✓✓rejects✓NaN/∞
Trigonometric and hyperboliccosfloat16✓≤1≤1≤1≤1≤1≤1≤1≤1≤1✓≤1
Trigonometric and hyperboliccosfloat8 E5M2✓✓✓✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Trigonometric and hyperboliccosfloat8 E4M3✓✓✓✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Trigonometric and hyperboliccosTF32✓
Trigonometric and hyperboliccosposit16✓
Trigonometric and hyperbolictanfloat64✓≤12≤12≤12≤12rejectsrejects≤1
Trigonometric and hyperbolictanfloat32✓≤13≤13≤18,388,60738,388,607≤1rejects≤1
Trigonometric and hyperbolictanbfloat16✓✓✓✓✓✓127✓127rejectsrejects✓
Trigonometric and hyperbolictanfloat16✓≤1≤1≤1≤1≤1≤1≤1≤1≤1rejects≤1
Trigonometric and hyperbolictanfloat8 E5M2✓✓✓≤1≤1rejectsrejects✓rejectsrejectsrejectsrejects
Trigonometric and hyperbolictanfloat8 E4M3✓✓✓✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Trigonometric and hyperbolictanTF32✓
Trigonometric and hyperbolictanposit16✓
Trigonometric and hyperbolicasinfloat64✓≤124,503,599,627,370,4952≤12≤12rejectsrejects≤1
Trigonometric and hyperbolicasinfloat32✓≤1≤12≤18,388,6078,388,60838,388,6074rejects≤1
Trigonometric and hyperbolicasinbfloat16✓✓✓≤1✓✓127✓127rejectsrejects✓
Trigonometric and hyperbolicasinfloat16✓≤1≤1≤1≤1✓≤1≤1≤1✓rejects✓
Trigonometric and hyperbolicasinfloat8 E5M2✓✓✓≤1✓rejectsrejects✓rejectsrejectsrejectsrejects
Trigonometric and hyperbolicasinfloat8 E4M3✓✓✓≤1✓rejectsrejects✓rejectsrejectsrejectsrejects
Trigonometric and hyperbolicasinTF32✓
Trigonometric and hyperbolicasinposit16✓
Trigonometric and hyperbolicacosfloat64✓≤1≤1≤1≤1≤12≤1≤1rejectsrejects≤1
Trigonometric and hyperbolicacosfloat32✓≤1≤12≤1422≤14rejects≤1
Trigonometric and hyperbolicacosbfloat16✓✓✓≤1✓✓✓✓✓rejectsrejects✓
Trigonometric and hyperbolicacosfloat16✓≤1≤1≤1≤1≤1≤1≤1≤1≤1rejects≤1
Trigonometric and hyperbolicacosfloat8 E5M2✓✓✓≤1✓rejectsrejects✓rejectsrejectsrejectsrejects
Trigonometric and hyperbolicacosfloat8 E4M3✓✓✓≤1≤1rejectsrejects✓rejectsrejectsrejectsrejects
Trigonometric and hyperbolicacosTF32✓
Trigonometric and hyperbolicacosposit16✓
Trigonometric and hyperbolicatanfloat64✓≤1≤14,437,541,851,369,665≤14,503,599,627,370,495≤1≤1≤1rejectsrejects≤1
Trigonometric and hyperbolicatanfloat32✓≤1≤18,383,327≤18,388,6078,388,60728,388,6073rejects≤1
Trigonometric and hyperbolicatanbfloat16✓✓✓127✓✓127✓127rejectsrejects✓
Trigonometric and hyperbolicatanfloat16✓≤1≤1≤1≤1≤1≤1≤1≤1≤1rejects≤1
Trigonometric and hyperbolicatanfloat8 E5M2✓✓✓✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Trigonometric and hyperbolicatanfloat8 E4M3✓✓✓≤1≤1rejectsrejects✓rejectsrejectsrejectsrejects
Trigonometric and hyperbolicatanTF32✓
Trigonometric and hyperbolicatanposit16✓
Trigonometric and hyperbolicatan2float64✓≤129,218,230,760,605,459,92024,605,249,457,297,304,8572≤12rejectsrejects≤1
Trigonometric and hyperbolicatan2float32✓≤12NaN/∞21,061,752,7941,070,141,40321,070,141,403rejectsrejects≤1
Trigonometric and hyperbolicatan2bfloat16✓≤1≤1NaN/∞≤1NaN/∞16,329≤116,329rejectsrejects≤1
Trigonometric and hyperbolicatan2float16✓≤1≤1≤1≤1≤1≤1≤1≤1rejectsrejects≤1
Trigonometric and hyperbolicatan2float8 E5M2✓≤1≤1≤1≤1rejectsrejects≤1rejectsrejectsrejectsrejects
Trigonometric and hyperbolicatan2float8 E4M3✓✓✓≤1≤1rejectsrejects✓rejectsrejectsrejectsrejects
Trigonometric and hyperbolicatan2TF32✓
Trigonometric and hyperbolicatan2posit16conv
Trigonometric and hyperbolicsinhfloat64✓NaN/∞≤14,503,599,627,370,495≤12496≤1≤1rejectsrejects2
Trigonometric and hyperbolicsinhfloat32✓NaN/∞28,388,607228,388,607≤18,388,6072rejects2
Trigonometric and hyperbolicsinhbfloat16✓NaN/∞✓127✓✓127✓127rejectsrejects✓
Trigonometric and hyperbolicsinhfloat16✓≤1✓≤1✓≤1≤1≤1✓≤1rejects≤1
Trigonometric and hyperbolicsinhfloat8 E5M2✓✓✓✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Trigonometric and hyperbolicsinhfloat8 E4M3✓convconv✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Trigonometric and hyperbolicsinhTF32✓
Trigonometric and hyperbolicsinhposit16✓
Trigonometric and hyperboliccoshfloat64✓NaN/∞≤1496≤12496≤1≤1rejectsrejects2
Trigonometric and hyperboliccoshfloat32✓NaN/∞2242225222rejects2
Trigonometric and hyperboliccoshbfloat16✓NaN/∞✓✓✓✓✓✓✓rejectsrejects✓
Trigonometric and hyperboliccoshfloat16✓≤1≤1≤1≤1≤1≤1✓≤1≤1rejects≤1
Trigonometric and hyperboliccoshfloat8 E5M2✓✓✓✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Trigonometric and hyperboliccoshfloat8 E4M3✓convconv✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Trigonometric and hyperboliccoshTF32✓
Trigonometric and hyperboliccoshposit16✓
Trigonometric and hyperbolictanhfloat64✓≤1≤14,503,599,627,370,495≤14,503,599,627,370,495≤1≤1≤17≤12
Trigonometric and hyperbolictanhfloat32✓≤12458,388,6075≤18,388,60710322
Trigonometric and hyperbolictanhbfloat16✓✓✓✓✓127127✓127rejects✓✓
Trigonometric and hyperbolictanhfloat16✓✓✓✓✓≤1✓✓✓✓✓✓
Trigonometric and hyperbolictanhfloat8 E5M2✓✓✓✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Trigonometric and hyperbolictanhfloat8 E4M3✓✓✓✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Trigonometric and hyperbolictanhTF32✓
Trigonometric and hyperbolictanhposit16✓
Trigonometric and hyperbolicasinhfloat64✓≤124,503,599,627,370,4952≤12≤12rejectsrejects≤1
Trigonometric and hyperbolicasinhfloat32✓228,388,607228,388,607≤18,388,6072rejects2
Trigonometric and hyperbolicasinhbfloat16✓✓✓127✓✓127✓127rejectsrejects✓
Trigonometric and hyperbolicasinhfloat16✓≤1≤1≤1≤1≤1≤1≤1≤1≤1rejects≤1
Trigonometric and hyperbolicasinhfloat8 E5M2✓✓✓≤1✓rejectsrejects✓rejectsrejectsrejectsrejects
Trigonometric and hyperbolicasinhfloat8 E4M3✓✓✓≤1✓rejectsrejects✓rejectsrejectsrejectsrejects
Trigonometric and hyperbolicasinhTF32✓
Trigonometric and hyperbolicasinhposit16✓
Trigonometric and hyperbolicacoshfloat64✓223223≤12rejectsrejects2
Trigonometric and hyperbolicacoshfloat32✓224223≤122rejects2
Trigonometric and hyperbolicacoshbfloat16✓✓✓2✓✓✓✓✓rejectsrejects✓
Trigonometric and hyperbolicacoshfloat16✓≤1≤12≤1≤12≤1≤1≤1rejects≤1
Trigonometric and hyperbolicacoshfloat8 E5M2✓✓✓≤1✓rejectsrejects✓rejectsrejectsrejectsrejects
Trigonometric and hyperbolicacoshfloat8 E4M3✓✓✓≤1✓rejectsrejects✓rejectsrejectsrejectsrejects
Trigonometric and hyperbolicacoshTF32✓
Trigonometric and hyperbolicacoshposit16✓
Trigonometric and hyperbolicatanhfloat64✓≤124,503,599,627,370,49524,503,599,627,370,4952≤12rejectsrejects2
Trigonometric and hyperbolicatanhfloat32✓≤138,388,60738,388,6078,388,607≤18,388,6072rejects2
Trigonometric and hyperbolicatanhbfloat16✓✓✓127✓✓127✓127rejectsrejects✓
Trigonometric and hyperbolicatanhfloat16✓✓✓≤1✓✓≤1✓✓✓rejects✓
Trigonometric and hyperbolicatanhfloat8 E5M2✓✓✓✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Trigonometric and hyperbolicatanhfloat8 E4M3✓convconv≤1✓rejectsrejects✓rejectsrejectsrejectsrejects
Trigonometric and hyperbolicatanhTF32✓
Trigonometric and hyperbolicatanhposit16✓
Activationsrelufloat64✓±0✓4,503,599,627,370,495✓4,503,599,627,370,495✓✓✓±0✓✓
Activationsrelufloat32✓±0✓8,388,607✓8,388,607✓✓8,388,607±0✓✓
Activationsrelubfloat16✓±0✓127✓127127✓127rejects✓✓
Activationsrelufloat16✓±0✓✓✓±0✓±0✓±0✓✓
Activationsrelufloat8 E5M2✓±0✓✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Activationsrelufloat8 E4M3✓±0✓✓✓rejectsrejects✓rejectsrejectsrejectsrejects
ActivationsreluTF32✓
ActivationsleakyReLUfloat64✓✓✓4,458,280,719,818,338✓4,503,599,627,370,495201,326,592·✓rejects201,326,592✓
ActivationsleakyReLUfloat32✓✓✓8,382,891✓8,388,6078,382,891·8,388,607✓✓✓
ActivationsleakyReLUbfloat16✓✓✓127✓127127·rejectsrejectsrejects✓
ActivationsleakyReLUfloat16✓✓✓✓✓✓✓·✓✓✓✓
ActivationsleakyReLUfloat8 E5M2✓✓✓✓✓rejectsrejects·rejectsrejectsrejectsrejects
ActivationsleakyReLUfloat8 E4M3✓✓✓✓✓rejectsrejects·rejectsrejectsrejectsrejects
ActivationsleakyReLUTF32✓
Activationselufloat64✓≤1≤14,503,599,627,370,495≤14,363,961,458,896,588,046≤1·≤1rejects4,363,961,458,896,588,0464,494,587,992,567,547,063
Activationselufloat32✓≤1≤18,388,607≤1855,612,3178,388,607·8,388,607855,612,317867,240,451855,612,317
Activationselubfloat16✓✓✓✓✓15,10415,104·rejectsrejectsrejects15,104
Activationselufloat16✓✓✓✓✓3,072✓·✓≤13,0723,072
Activationselufloat8 E5M2✓✓✓✓✓rejectsrejects·rejectsrejectsrejectsrejects
Activationselufloat8 E4M3≤1✓✓✓✓rejectsrejects·rejectsrejectsrejectsrejects
ActivationseluTF32✓
Activationssigmoidfloat64≤11,077,003,997,787,0601,077,003,997,787,0604,383,635,548,707,5541,077,003,997,787,0604,383,635,548,707,5541,077,003,997,787,060·1,077,003,997,787,0604,368,136,721,604,654,1464,368,136,721,604,654,1464,035,191,066,499,671,904
Activationssigmoidfloat32≤12,080,6572,080,6578,335,9482,080,6578,335,9488,335,948·8,335,948869,987,759864,023,2634,320,642
Activationssigmoidbfloat16≤1242410924109109·rejectsrejects15,22740
Activationssigmoidfloat16≤1≤1≤12552552255·rejects2≤1255
Activationssigmoidfloat8 E5M2≤1✓✓≤1✓rejectsrejects·rejectsrejectsrejectsrejects
Activationssigmoidfloat8 E4M3≤1✓✓NaN/∞≤1rejectsrejects·rejectsrejectsrejectsrejects
ActivationssigmoidTF32≤1
Activationssoftplusfloat64≤1577,689577,6894,336,391,769,732,24124,336,391,769,732,2417≤12rejects4,368,281,163,086,985,6074,037,088,397,506,071,124
Activationssoftplusfloat32≤1≤128,324,88928,324,8898,324,889≤18,324,8894864,016,3225,922,629
Activationssoftplusbfloat16≤1✓✓109≤1109109✓109rejects15,22766
Activationssoftplusfloat16≤1≤1≤1≤1≤1≤1≤1≤1≤1≤14,095≤1
Activationssoftplusfloat8 E5M2≤1✓✓≤1≤1rejectsrejects✓rejectsrejectsrejectsrejects
Activationssoftplusfloat8 E4M3≤1✓✓≤1≤1rejectsrejects✓rejectsrejectsrejectsrejects
ActivationssoftplusTF32≤1
Activationssilufloat64≤137,469,013,202,615,48537,469,013,202,615,48546,684,722,066,868,43537,469,013,202,615,48546,684,722,066,868,43537,469,013,202,615,485·37,469,013,202,615,4854,391,604,047,841,785,9564,391,604,047,841,785,9564,063,996,846,656,982,301
Activationssilufloat32245,177,54645,177,54661,755,09845,177,54661,755,09861,755,098·61,755,098906,872,270897,899,16653,785,709
Activationssilubfloat162647647917647917917·rejectsrejects15,534733
Activationssilufloat163NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞·rejectsNaN/∞NaN/∞NaN/∞
Activationssilufloat8 E5M22NaN/∞NaN/∞NaN/∞NaN/∞rejectsrejects·rejectsrejectsrejectsrejects
Activationssilufloat8 E4M3≤1✓✓NaN/∞✓rejectsrejects·rejectsrejectsrejectsrejects
ActivationssiluTF323
Activationsgelu (tanh)float644,054,502,521,738,645,4824,376,493,670,301,884,7334,371,964,506,724,811,7344,359,911,127,104,447,5594,371,964,506,724,811,7344,389,155,536,157,995,1634,371,964,506,724,811,734·4,371,964,506,724,811,7344,389,155,536,157,995,1634,371,964,506,724,811,7344,371,964,506,724,811,734
Activationsgelu (tanh)float32783,914,749874,609,976866,371,151890,448,356890,448,356892,260,845892,360,932·866,371,1511,767,538,089866,371,151866,371,151
Activationsgelu (tanh)bfloat1615,12613,34513,19015,17113,58115,17115,171·15,171rejects15,17115,171
Activationsgelu (tanh)float161,179NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞·NaN/∞NaN/∞NaN/∞NaN/∞
Activationsgelu (tanh)float8 E5M242NaN/∞NaN/∞NaN/∞NaN/∞rejectsrejects·rejectsrejectsrejectsrejects
Activationsgelu (tanh)float8 E4M3NaN/∞✓✓NaN/∞≤1rejectsrejects·rejectsrejectsrejectsrejects
Activationsgelu (tanh)TF32115,867
Activationsgelu (erf)float64·4,373,181,763,526,858,2624,374,518,897,643,722,41622,357,023,797,964,722386,221,992,094,81622,357,023,797,964,722386,221,992,094,816·4,374,518,897,643,722,416rejects28NaN/∞
Activationsgelu (erf)float32·NaN/∞867,731,00030,136,097827,12130,136,09730,136,097·867,435,724867,259,96813NaN/∞
Activationsgelu (erf)bfloat16·NaN/∞13,2153206320320·rejectsrejects7NaN/∞
Activationsgelu (erf)float16·NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞·rejectsNaN/∞NaN/∞NaN/∞
Activationsgelu (erf)float8 E5M2·NaN/∞NaN/∞rejectsrejectsrejectsrejects·rejectsrejectsrejectsrejects
Activationsgelu (erf)float8 E4M3·✓✓rejectsrejectsrejectsrejects·rejectsrejectsrejectsrejects
Activationserffloat64·≤1≤15,081,767,996,463,980≤15,081,767,996,463,9803·≤1rejects≤14,506,851,574,766,186,488
Activationserffloat32·≤1≤19,465,52959,465,5299,465,531·9,465,529≤1≤1878,465,300
Activationserfbfloat16·13,404✓143✓143143·rejectsrejects✓13,404
Activationserffloat16·5✓≤1✓✓≤1·rejects✓✓5
Activationserffloat8 E5M2·✓✓✓rejectsrejectsrejects·rejectsrejectsrejectsrejects
Activationserffloat8 E4M3·✓✓✓rejectsrejectsrejects·rejectsrejectsrejectsrejects
Guarded operationssafeLogfloat64NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞rejectsNaN/∞NaN/∞
Guarded operationssafeLogfloat32NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞
Guarded operationssafeLogbfloat16NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞rejectsrejectsNaN/∞
Guarded operationssafeLogfloat16NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞
Guarded operationssafeLogfloat8 E5M2NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞rejectsNaN/∞NaN/∞rejects
Guarded operationssafeLogfloat8 E4M3NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞rejectsNaN/∞NaN/∞rejects
Guarded operationssafeLogTF32NaN/∞
Guarded operationssafeInvfloat64≤1≤1≤14,434,805,660,482,884≤14,434,805,660,482,884≤1≤1≤1≤1≤1≤1
Guarded operationssafeInvfloat32≤1≤1≤18,360,79428,360,7948,360,794≤18,360,794≤1≤1≤1
Guarded operationssafeInvbfloat16≤1≤1≤1127✓128127≤1127rejects≤1≤1
Guarded operationssafeInvfloat16≤1≤1≤1≤1≤1≤1≤1≤1≤1≤1≤1≤1
Guarded operationssafeInvfloat8 E5M2✓✓✓≤1✓rejectsrejects≤1rejectsrejectsrejectsrejects
Guarded operationssafeInvfloat8 E4M3✓convconv≤1✓rejectsrejects≤1rejectsrejectsrejectsrejects
Guarded operationssafeInvTF32≤1
Guarded operationssafeDivfloat64≤1≤1≤194,158,327,512,039,422≤194,158,327,512,039,422≤1≤1≤1≤1≤1≤1
Guarded operationssafeDivfloat32≤1≤1≤1189,386,5872189,386,587189,386,587≤1189,386,587≤1≤1≤1
Guarded operationssafeDivbfloat16≤1≤1≤12,926≤12,9262,926≤12,926rejects≤1≤1
Guarded operationssafeDivfloat16≤1NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞≤1NaN/∞NaN/∞
Guarded operationssafeDivfloat8 E5M2✓≤1≤1NaN/∞≤1rejectsrejectsNaN/∞rejectsrejectsrejectsrejects
Guarded operationssafeDivfloat8 E4M3≤1convconvNaN/∞≤1rejectsrejectsNaN/∞rejectsrejectsrejectsrejects
Guarded operationssafeDivTF32≤1
Guarded operationssmoothAbsfloat64≤1NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞
Guarded operationssmoothAbsfloat32≤1NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞
Guarded operationssmoothAbsbfloat16≤1NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞rejectsNaN/∞NaN/∞
Guarded operationssmoothAbsfloat162NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞≤1NaN/∞NaN/∞
Guarded operationssmoothAbsfloat8 E5M2≤1✓✓NaN/∞NaN/∞✓✓NaN/∞rejects≤1≤1rejects
Guarded operationssmoothAbsfloat8 E4M3≤1✓✓NaN/∞NaN/∞✓✓NaN/∞rejects✓✓rejects
Guarded operationssmoothAbsTF322
Guarded operationsnanToNumfloat64✓✓✓✓✓4,503,599,627,370,495✓✓✓✓✓178,956,971
Guarded operationsnanToNumfloat32✓✓✓✓✓8,388,607✓✓✓✓✓✓
Guarded operationsnanToNumbfloat16✓✓✓✓✓127✓NaN/∞32,639rejects✓✓
Guarded operationsnanToNumfloat16✓✓✓✓✓✓✓✓✓✓✓✓
Guarded operationsnanToNumfloat8 E5M2✓NaN/∞NaN/∞✓✓NaN/∞NaN/∞NaN/∞rejects≤1≤1rejects
Guarded operationsnanToNumfloat8 E4M3✓✓✓✓✓NaN/∞NaN/∞NaN/∞rejects✓✓rejects
Guarded operationsnanToNumTF32✓
Guarded operationsclampfloat64✓±0✓4,503,599,627,370,495✓9,214,364,837,600,034,8169,214,364,837,600,034,816±0±0±0±0✓
Guarded operationsclampfloat32✓±0✓8,388,607✓2,130,706,4322,130,706,432±08,370,869±0±0✓
Guarded operationsclampbfloat16✓±0✓127✓32,51232,512✓✓rejectsrejects✓
Guarded operationsclampfloat16✓±0✓✓✓30,72030,720±0±0±0±0✓
Guarded operationsclampfloat8 E5M2✓±0✓✓✓120120✓rejects✓✓rejects
Guarded operationsclampfloat8 E4M3✓±0✓✓✓112112✓rejects✓✓rejects
Guarded operationsclampTF32✓
Comparisons and selectionmaxfloat64✓±0✓4,503,599,627,370,495✓4,503,599,627,370,495±0±0✓±0±0±0
Comparisons and selectionmaxfloat32✓±0✓8,388,607✓8,388,60716,652,956±08,388,607±0±0±0
Comparisons and selectionmaxbfloat16✓±0✓127✓127252±0127rejects✓±0
Comparisons and selectionmaxfloat16✓±0✓✓✓±0±0±0✓±0✓±0
Comparisons and selectionmaxfloat8 E5M2✓±0✓✓✓rejectsrejects±0rejectsrejectsrejectsrejects
Comparisons and selectionmaxfloat8 E4M3✓±0✓✓✓rejectsrejects±0rejectsrejectsrejectsrejects
Comparisons and selectionmaxTF32✓
Comparisons and selectionminfloat64✓±0✓4,503,599,627,370,495✓4,503,599,627,370,495±0±0✓±0±0±0
Comparisons and selectionminfloat32✓±0✓8,388,607✓8,388,60716,435,590±08,388,607±0±0±0
Comparisons and selectionminbfloat16✓±0✓127✓127230±0127rejects✓±0
Comparisons and selectionminfloat16✓±0✓✓✓±0±0±0✓±0✓±0
Comparisons and selectionminfloat8 E5M2✓±0✓✓✓rejectsrejects±0rejectsrejectsrejectsrejects
Comparisons and selectionminfloat8 E4M3✓±0✓✓✓rejectsrejects±0rejectsrejectsrejectsrejects
Comparisons and selectionminTF32✓
Comparisons and selectionfmaxfloat64✓±0✓8,751,155,370,360,414±0··±0✓rejectsrejectsrejects
Comparisons and selectionfmaxfloat32✓±0✓16,545,804±0··±08,388,607rejectsrejectsrejects
Comparisons and selectionfmaxbfloat16✓±0✓252±0··±0127rejectsrejectsrejects
Comparisons and selectionfmaxfloat16✓±0✓±0±0··±0✓rejectsrejectsrejects
Comparisons and selectionfmaxfloat8 E5M2✓±0✓±0±0··±0rejectsrejectsrejectsrejects
Comparisons and selectionfmaxfloat8 E4M3✓±0✓±0±0··±0rejectsrejectsrejectsrejects
Comparisons and selectionfmaxTF32✓
Comparisons and selectionfminfloat64✓±0✓5,485,116,409,050,824±0··±0✓rejectsrejectsrejects
Comparisons and selectionfminfloat32✓±0✓16,531,008±0··±08,388,607rejectsrejectsrejects
Comparisons and selectionfminbfloat16✓±0✓254±0··±0127rejectsrejectsrejects
Comparisons and selectionfminfloat16✓±0✓±0±0··±0✓rejectsrejectsrejects
Comparisons and selectionfminfloat8 E5M2✓±0✓±0±0··±0rejectsrejectsrejectsrejects
Comparisons and selectionfminfloat8 E4M3✓±0✓±0±0··±0rejectsrejectsrejectsrejects
Comparisons and selectionfminTF32✓
Comparisons and selectioneqfloat64✓✓✓✓✓✓✓✓✓✓✓✓
Comparisons and selectioneqfloat32✓✓✓✓✓✓✓✓✓✓✓✓
Comparisons and selectioneqbfloat16✓✓✓✓✓✓✓✓✓rejectsrejects✓
Comparisons and selectioneqfloat16✓✓✓✓✓✓✓✓✓✓✓✓
Comparisons and selectioneqfloat8 E5M2✓✓✓✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Comparisons and selectioneqfloat8 E4M3✓✓✓✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Comparisons and selectioneqTF32✓
Comparisons and selectionnefloat64✓✓✓✓✓✓✓✓✓✓✓✓
Comparisons and selectionnefloat32✓✓✓✓✓✓✓✓✓✓✓✓
Comparisons and selectionnebfloat16✓✓✓✓✓✓✓✓✓rejectsrejects✓
Comparisons and selectionnefloat16✓✓✓✓✓✓✓✓✓✓✓✓
Comparisons and selectionnefloat8 E5M2✓✓✓✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Comparisons and selectionnefloat8 E4M3✓✓✓✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Comparisons and selectionneTF32✓
Comparisons and selectionltfloat64✓✓✓✓✓✓✓✓✓✓✓✓
Comparisons and selectionltfloat32✓✓✓✓✓✓✓✓✓✓✓✓
Comparisons and selectionltbfloat16✓✓✓✓✓✓✓✓✓rejectsrejects✓
Comparisons and selectionltfloat16✓✓✓✓✓✓✓✓✓✓✓✓
Comparisons and selectionltfloat8 E5M2✓✓✓✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Comparisons and selectionltfloat8 E4M3✓✓✓✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Comparisons and selectionltTF32✓
Comparisons and selectionlefloat64✓✓✓✓✓✓✓✓✓✓✓✓
Comparisons and selectionlefloat32✓✓✓✓✓✓✓✓✓✓✓✓
Comparisons and selectionlebfloat16✓✓✓✓✓✓✓✓✓rejectsrejects✓
Comparisons and selectionlefloat16✓✓✓✓✓✓✓✓✓✓✓✓
Comparisons and selectionlefloat8 E5M2✓✓✓✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Comparisons and selectionlefloat8 E4M3✓✓✓✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Comparisons and selectionleTF32✓
Comparisons and selectiongtfloat64✓✓✓✓✓✓✓✓✓✓✓✓
Comparisons and selectiongtfloat32✓✓✓✓✓✓✓✓✓✓✓✓
Comparisons and selectiongtbfloat16✓✓✓✓✓✓✓✓✓rejectsrejects✓
Comparisons and selectiongtfloat16✓✓✓✓✓✓✓✓✓✓✓✓
Comparisons and selectiongtfloat8 E5M2✓✓✓✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Comparisons and selectiongtfloat8 E4M3✓✓✓✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Comparisons and selectiongtTF32✓
Comparisons and selectiongefloat64✓✓✓✓✓✓✓✓✓✓✓✓
Comparisons and selectiongefloat32✓✓✓✓✓✓✓✓✓✓✓✓
Comparisons and selectiongebfloat16✓✓✓✓✓✓✓✓✓rejectsrejects✓
Comparisons and selectiongefloat16✓✓✓✓✓✓✓✓✓✓✓✓
Comparisons and selectiongefloat8 E5M2✓✓✓✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Comparisons and selectiongefloat8 E4M3✓✓✓✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Comparisons and selectiongeTF32✓
Comparisons and selectionisNaNfloat64✓✓✓✓✓✓✓✓✓✓✓✓
Comparisons and selectionisNaNfloat32✓✓✓✓✓✓✓✓✓✓✓✓
Comparisons and selectionisNaNbfloat16✓✓✓✓✓✓✓✓✓✓✓✓
Comparisons and selectionisNaNfloat16✓✓✓✓✓✓✓✓✓✓✓✓
Comparisons and selectionisNaNfloat8 E5M2✓✓✓✓✓rejectsrejects✓rejects✓✓rejects
Comparisons and selectionisNaNfloat8 E4M3✓✓✓✓✓rejectsrejects✓rejects✓✓rejects
Comparisons and selectionisNaNTF32✓
Comparisons and selectionisInffloat64✓✓✓✓✓✓✓✓✓✓✓✓
Comparisons and selectionisInffloat32✓✓✓✓✓✓✓✓✓✓✓✓
Comparisons and selectionisInfbfloat16✓✓✓✓✓✓✓✓✓✓✓✓
Comparisons and selectionisInffloat16✓✓✓✓✓✓✓✓✓✓✓✓
Comparisons and selectionisInffloat8 E5M2✓✓✓✓✓rejectsrejects✓rejects✓✓rejects
Comparisons and selectionisInffloat8 E4M3✓✓✓✓✓rejectsrejects✓rejects✓✓rejects
Comparisons and selectionisInfTF32✓
Comparisons and selectionisFinitefloat64✓✓✓✓✓✓✓✓✓✓✓✓
Comparisons and selectionisFinitefloat32✓✓✓✓✓✓✓✓✓✓✓✓
Comparisons and selectionisFinitebfloat16✓✓✓✓✓✓✓✓✓✓✓✓
Comparisons and selectionisFinitefloat16✓✓✓✓✓✓✓✓✓✓✓✓
Comparisons and selectionisFinitefloat8 E5M2✓✓✓✓✓rejectsrejects✓rejects✓✓rejects
Comparisons and selectionisFinitefloat8 E4M3✓✓✓✓✓rejectsrejects✓rejects✓✓rejects
Comparisons and selectionisFiniteTF32✓
Comparisons and selectionselectfloat64✓✓✓✓✓✓✓✓✓✓✓✓
Comparisons and selectionselectfloat32✓✓✓✓✓✓✓✓✓✓✓✓
Comparisons and selectionselectbfloat16✓✓✓✓✓✓✓✓✓rejects✓✓
Comparisons and selectionselectfloat16✓✓✓✓✓✓✓✓✓✓✓✓
Comparisons and selectionselectfloat8 E5M2✓✓✓✓✓✓✓✓·≤1≤1·
Comparisons and selectionselectfloat8 E4M3✓✓✓✓✓✓✓✓·✓✓·
Comparisons and selectionselectTF32✓
Reductions, scans and sortingreduce sumfloat64≤11282561502348121,324812≤1≤1≤1≤1
Reductions, scans and sortingreduce sumfloat32≤14003846521172159169≤1✓✓≤1
Reductions, scans and sortingreduce sumbfloat16≤1≤1±0✓✓✓✓168✓rejects✓≤1
Reductions, scans and sortingreduce sumfloat16NaN/∞±0±0✓✓NaN/∞NaN/∞✓NaN/∞✓✓NaN/∞
Reductions, scans and sortingreduce sumfloat8 E5M2NaN/∞±0±0NaN/∞NaN/∞rejectsrejectsNaN/∞rejectsrejectsrejectsrejects
Reductions, scans and sortingreduce sumfloat8 E4M3✓±0±0152✓rejectsrejectsNaN/∞rejectsrejectsrejectsrejects
Reductions, scans and sortingreduce sumTF322
Reductions, scans and sortingreduce prodfloat64✓911679810✓✓✓✓
Reductions, scans and sortingreduce prodfloat32✓88968710✓✓✓✓
Reductions, scans and sortingreduce prodbfloat16≤17✓✓✓988✓rejectsrejects≤1
Reductions, scans and sortingreduce prodfloat16✓NaN/∞≤1✓✓89✓✓✓✓✓
Reductions, scans and sortingreduce prodfloat8 E5M2✓✓✓14NaN/∞rejectsrejects11rejectsrejectsrejectsrejects
Reductions, scans and sortingreduce prodfloat8 E4M3≤1convconv13≤1rejectsrejectsNaN/∞rejectsrejectsrejectsrejects
Reductions, scans and sortingreduce prodTF32≤1
Reductions, scans and sortingreduce maxfloat64✓±0±0✓✓✓✓✓✓✓✓✓
Reductions, scans and sortingreduce maxfloat32✓±0±0✓✓✓✓✓✓✓✓✓
Reductions, scans and sortingreduce maxbfloat16✓±0±0✓✓✓✓✓✓rejectsrejects✓
Reductions, scans and sortingreduce maxfloat16✓±0±0✓✓✓NaN/∞✓✓✓✓✓
Reductions, scans and sortingreduce maxfloat8 E5M2✓±0±0✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Reductions, scans and sortingreduce maxfloat8 E4M3✓±0±0✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Reductions, scans and sortingreduce maxTF32✓
Reductions, scans and sortingreduce minfloat64✓±0±0✓✓✓✓✓✓✓✓✓
Reductions, scans and sortingreduce minfloat32✓±0±0✓✓✓✓✓✓✓✓✓
Reductions, scans and sortingreduce minbfloat16✓±0±0✓✓✓✓✓✓rejectsrejects✓
Reductions, scans and sortingreduce minfloat16✓±0±0✓✓✓NaN/∞✓✓✓✓✓
Reductions, scans and sortingreduce minfloat8 E5M2✓±0±0✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Reductions, scans and sortingreduce minfloat8 E4M3✓±0±0✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Reductions, scans and sortingreduce minTF32✓
Reductions, scans and sortingmeanfloat64≤19,007,199,254,740,99351223235966162≤1≤1≤1≤1
Reductions, scans and sortingmeanfloat32≤116,777,2175361091173301,7182,378≤1✓✓≤1
Reductions, scans and sortingmeanbfloat16≤1257±0✓✓✓✓499✓rejects✓≤1
Reductions, scans and sortingmeanfloat16NaN/∞≤1±0✓✓NaN/∞✓✓✓✓✓NaN/∞
Reductions, scans and sortingmeanfloat8 E5M2NaN/∞±0±0NaN/∞NaN/∞rejectsrejectsNaN/∞rejectsrejectsrejectsrejects
Reductions, scans and sortingmeanfloat8 E4M3✓±0±0NaN/∞NaN/∞rejectsrejectsNaN/∞rejectsrejectsrejectsrejects
Reductions, scans and sortingmeanTF322
Reductions, scans and sortingcumsumfloat64≤12,372,847477,96914,91614,9162,3392,0132,339≤1≤1≤1≤1
Reductions, scans and sortingcumsumfloat32≤1✓62,52881,03481,03416,0826,86616,082≤1≤1≤1≤1
Reductions, scans and sortingcumsumbfloat16≤1≤134,45132,41231,99032,89032,41832,890rejectsrejectsrejects≤1
Reductions, scans and sortingcumsumfloat16NaN/∞137NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞✓NaN/∞NaN/∞
Reductions, scans and sortingcumsumfloat8 E5M2NaN/∞✓✓NaN/∞NaN/∞rejectsrejectsNaN/∞rejectsrejectsrejectsrejects
Reductions, scans and sortingcumsumfloat8 E4M3✓convconv176150rejectsrejectsNaN/∞rejectsrejectsrejectsrejects
Reductions, scans and sortingcumsumTF322
Reductions, scans and sortingcumprodfloat64✓10977101310≤1✓rejects✓
Reductions, scans and sortingcumprodfloat32✓✓1299111211≤1✓rejects✓
Reductions, scans and sortingcumprodbfloat16≤1✓1193101010rejectsrejectsrejects≤1
Reductions, scans and sortingcumprodfloat16✓≤1NaN/∞88NaN/∞NaN/∞NaN/∞≤1✓rejects✓
Reductions, scans and sortingcumprodfloat8 E5M2✓✓✓102rejectsrejects11rejectsrejectsrejectsrejects
Reductions, scans and sortingcumprodfloat8 E4M3≤1convconv9NaN/∞rejectsrejectsNaN/∞rejectsrejectsrejectsrejects
Reductions, scans and sortingcumprodTF32≤1
Reductions, scans and sortingcummaxfloat64✓±0±0✓✓··✓rejectsrejectsrejects✓
Reductions, scans and sortingcummaxfloat32✓±0±08,278,312✓··✓rejectsrejectsrejects✓
Reductions, scans and sortingcummaxbfloat16✓±0±074✓··✓rejectsrejectsrejects✓
Reductions, scans and sortingcummaxfloat16✓±0±0✓✓··✓rejectsrejectsrejects✓
Reductions, scans and sortingcummaxfloat8 E5M2✓±0±0✓✓··✓rejectsrejectsrejectsrejects
Reductions, scans and sortingcummaxfloat8 E4M3✓±0±0✓✓··✓rejectsrejectsrejectsrejects
Reductions, scans and sortingcummaxTF32✓
Reductions, scans and sortingcumminfloat64✓±0±0✓✓··✓rejectsrejectsrejects✓
Reductions, scans and sortingcumminfloat32✓±0±0✓✓··✓rejectsrejectsrejects✓
Reductions, scans and sortingcumminbfloat16✓±0±0✓✓··✓rejectsrejectsrejects✓
Reductions, scans and sortingcumminfloat16✓±0±0✓✓··✓rejectsrejectsrejects✓
Reductions, scans and sortingcumminfloat8 E5M2✓±0±0✓✓··✓rejectsrejectsrejectsrejects
Reductions, scans and sortingcumminfloat8 E4M3✓±0±0✓✓··✓rejectsrejectsrejectsrejects
Reductions, scans and sortingcumminTF32✓
Reductions, scans and sortingargmaxfloat64✓✓✓✓✓✓✓✓✓✓✓✓
Reductions, scans and sortingargmaxfloat32✓✓✓✓✓✓✓✓✓✓✓✓
Reductions, scans and sortingargmaxbfloat16✓✓✓✓✓✓✓✓✓rejectsrejects✓
Reductions, scans and sortingargmaxfloat16✓✓✓✓✓✓✓✓✓✓✓✓
Reductions, scans and sortingargmaxfloat8 E5M2✓✓✓✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Reductions, scans and sortingargmaxfloat8 E4M3✓✓✓✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Reductions, scans and sortingargmaxTF32✓
Reductions, scans and sortingargminfloat64✓✓✓✓✓✓✓✓✓✓✓✓
Reductions, scans and sortingargminfloat32✓✓✓✓✓✓✓✓✓✓✓✓
Reductions, scans and sortingargminbfloat16✓✓✓✓✓✓✓✓✓rejectsrejects✓
Reductions, scans and sortingargminfloat16✓✓✓✓✓✓✓✓✓✓✓✓
Reductions, scans and sortingargminfloat8 E5M2✓✓✓✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Reductions, scans and sortingargminfloat8 E4M3✓✓✓✓✓rejectsrejects✓rejectsrejectsrejectsrejects
Reductions, scans and sortingargminTF32✓
Reductions, scans and sortingsortfloat64✓✓✓4,249,066,248,055,019✓✓✓✓✓✓✓✓
Reductions, scans and sortingsortfloat32✓✓✓12,760,704✓✓✓✓✓✓✓✓
Reductions, scans and sortingsortbfloat16✓✓✓227✓✓✓✓rejectsrejectsrejects✓
Reductions, scans and sortingsortfloat16✓✓✓✓✓NaN/∞NaN/∞✓✓✓✓✓
Reductions, scans and sortingsortfloat8 E5M2✓✓✓✓✓rejectsrejectsNaN/∞rejectsrejectsrejectsrejects
Reductions, scans and sortingsortfloat8 E4M3✓✓✓✓✓rejectsrejectsNaN/∞rejectsrejectsrejectsrejects
Reductions, scans and sortingsortTF32✓
Reductions, scans and sortingsort descfloat64✓✓✓4,277,672,943,617,209±0✓✓✓✓✓✓rejects
Reductions, scans and sortingsort descfloat32✓✓✓13,325,040±0✓✓✓✓✓✓rejects
Reductions, scans and sortingsort descbfloat16✓✓✓248±0✓✓✓rejectsrejectsrejectsrejects
Reductions, scans and sortingsort descfloat16✓✓✓±0±0NaN/∞NaN/∞✓✓✓✓rejects
Reductions, scans and sortingsort descfloat8 E5M2✓✓✓±0±0rejectsrejectsNaN/∞rejectsrejectsrejectsrejects
Reductions, scans and sortingsort descfloat8 E4M3✓✓✓±0±0rejectsrejectsNaN/∞rejectsrejectsrejectsrejects
Reductions, scans and sortingsort descTF32✓
Reductions, scans and sortingtopkfloat64✓convconv✓✓✓✓convconv✓✓conv
Reductions, scans and sortingtopkfloat32✓convconv✓✓✓✓convconv✓✓conv
Reductions, scans and sortingtopkbfloat16✓convconv✓✓✓✓convrejectsrejectsrejectsconv
Reductions, scans and sortingtopkfloat16✓convconv✓✓✓✓convconv✓✓conv
Reductions, scans and sortingtopkfloat8 E5M2✓convconv✓✓✓✓conv·≤1≤1·
Reductions, scans and sortingtopkfloat8 E4M3✓convconv✓NaN/∞39NaN/∞conv·3939·
Reductions, scans and sortingtopkTF32✓
Reductions, scans and sortingtopKMaskfloat64✓conv✓✓✓✓✓convconv✓✓conv
Reductions, scans and sortingtopKMaskfloat32✓conv✓✓✓✓✓convconv✓✓conv
Reductions, scans and sortingtopKMaskbfloat16✓conv✓✓✓✓✓convrejectsrejectsrejectsconv
Reductions, scans and sortingtopKMaskfloat16✓conv✓✓✓✓✓convconv✓✓conv
Reductions, scans and sortingtopKMaskfloat8 E5M2✓conv✓✓✓✓✓conv·✓✓·
Reductions, scans and sortingtopKMaskfloat8 E4M3✓conv✓✓✓✓✓conv·✓✓·
Reductions, scans and sortingtopKMaskTF32✓
Softmax and lossessoftmaxfloat6431311332592571918·33434,021,4993,549,847,431
Softmax and lossessoftmaxfloat32≤166668,374,130671919·≤12≤17
Softmax and lossessoftmaxbfloat16✓≤1≤11235718≤1·≤1rejects✓≤1
Softmax and lossessoftmaxfloat162≤1≤1999≤1·3✓✓2
Softmax and lossessoftmaxfloat8 E5M23✓✓12≤1rejectsrejects·rejectsrejectsrejectsrejects
Softmax and lossessoftmaxfloat8 E4M3✓✓✓NaN/∞NaN/∞rejectsrejects·rejectsrejectsrejectsrejects
Softmax and lossessoftmaxTF322
Softmax and losseslogSoftmaxfloat64≤14,368,198,740,152,583,0284,368,198,740,152,583,0283,410,329,462,066,0863,410,329,462,066,0866,922,1446,922,144·6,922,1446,922,1444,494,691,807,354,678,9663,619,950,922
Softmax and losseslogSoftmaxfloat32≤1866,406,280865,235,712855,823,124855,823,124855,823,124855,823,124·855,823,124855,823,124855,823,124855,823,124
Softmax and losseslogSoftmaxbfloat16✓15,23113,24215,14615,14613,05913,059·13,059rejectsrejects16,269
Softmax and losseslogSoftmaxfloat16≤14,09621,8321,8323≤1·27≤1≤115,461
Softmax and losseslogSoftmaxfloat8 E5M2≤1≤1≤15617rejectsrejects·rejectsrejectsrejectsrejects
Softmax and losseslogSoftmaxfloat8 E4M3≤1≤1≤1NaN/∞NaN/∞rejectsrejects·rejectsrejectsrejectsrejects
Softmax and losseslogSoftmaxTF32✓
Softmax and lossesmaskedSoftmaxfloat64≤1≤1≤1≤1≤1≤1≤1≤1≤1≤1328,622,1553,549,847,431
Softmax and lossesmaskedSoftmaxfloat32≤1≤1≤1≤1≤1≤1≤1≤1≤1≤1≤17
Softmax and lossesmaskedSoftmaxbfloat16≤1convconv≤1≤1≤1conv≤1convrejectsconv≤1
Softmax and lossesmaskedSoftmaxfloat16≤1convconv≤1≤1≤1conv≤1≤1convconv≤1
Softmax and lossesmaskedSoftmaxfloat8 E5M2≤1convconv≤1≤1convconv≤1·convconv·
Softmax and lossesmaskedSoftmaxfloat8 E4M3≤1convconvNaN/∞≤1convconvNaN/∞·convconv·
Softmax and lossesmaskedSoftmaxTF32≤1
Softmax and lossescrossEntropyfloat64≤1≤1≤12≤1≤1≤1≤1≤12342,958,50888,734,404
Softmax and lossescrossEntropyfloat32≤12≤12≤12≤1≤1≤12456456
Softmax and lossescrossEntropybfloat16≤1≤1✓≤1≤1✓✓≤1≤1rejectsrejects124
Softmax and lossescrossEntropyfloat16✓≤1✓≤1≤1✓✓≤1≤1✓✓996
Softmax and lossescrossEntropyfloat8 E5M2≤1✓✓≤1≤1✓✓≤1·✓✓·
Softmax and lossescrossEntropyfloat8 E4M3✓✓✓NaN/∞NaN/∞✓✓✓·✓✓·
Softmax and lossescrossEntropyTF32✓
Softmax and lossescrossEntropyProbsfloat64≤1≤1≤1≤1≤1≤1≤1≤1≤1≤1≤1≤1
Softmax and lossescrossEntropyProbsfloat32≤1≤1≤1≤1≤1≤1≤1≤1≤1≤1≤1≤1
Softmax and lossescrossEntropyProbsbfloat16≤1≤1≤1≤1≤1≤1≤1✓✓rejectsrejects≤1
Softmax and lossescrossEntropyProbsfloat16✓✓✓✓✓✓✓✓✓✓✓✓
Softmax and lossescrossEntropyProbsfloat8 E5M2✓✓✓✓✓✓✓✓·✓✓·
Softmax and lossescrossEntropyProbsfloat8 E4M3✓✓✓✓✓✓✓✓·✓✓·
Softmax and lossescrossEntropyProbsTF32≤1
Softmax and lossesbinaryCrossEntropyfloat64✓✓✓74,07874,07874,07874,07874,07874,07874,07874,078✓
Softmax and lossesbinaryCrossEntropyfloat32✓✓✓NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞≤1
Softmax and lossesbinaryCrossEntropybfloat16≤1✓✓NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞rejectsrejects✓
Softmax and lossesbinaryCrossEntropyfloat16✓✓✓NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞✓NaN/∞✓
Softmax and lossesbinaryCrossEntropyfloat8 E5M2≤1✓✓✓✓✓✓✓·≤1≤1·
Softmax and lossesbinaryCrossEntropyfloat8 E4M3✓✓✓✓≤1✓✓✓·convconv·
Softmax and lossesbinaryCrossEntropyTF32✓
Softmax and lossesmseLossfloat64✓✓✓✓✓✓✓✓✓✓✓✓
Softmax and lossesmseLossfloat32≤1≤1✓≤1✓≤1✓≤1✓✓≤1≤1
Softmax and lossesmseLossbfloat16≤1≤1≤1≤1≤1≤1≤1≤1≤1rejects≤1≤1
Softmax and lossesmseLossfloat16≤1≤1≤1≤1≤1≤1≤1≤1≤1≤1≤1≤1
Softmax and lossesmseLossfloat8 E5M2≤1✓✓≤1≤1✓✓≤1·≤1≤1·
Softmax and lossesmseLossfloat8 E4M3✓convconv✓✓✓✓✓·convconv·
Softmax and lossesmseLossTF32≤1
Softmax and lossesmaeLossfloat64✓✓✓✓✓✓✓✓✓✓✓✓
Softmax and lossesmaeLossfloat32≤1≤1≤1≤1≤1≤1≤1≤1≤1≤1≤1≤1
Softmax and lossesmaeLossbfloat16≤1✓✓✓✓✓✓≤1✓rejects✓≤1
Softmax and lossesmaeLossfloat16NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞✓NaN/∞NaN/∞
Softmax and lossesmaeLossfloat8 E5M2NaN/∞✓✓NaN/∞NaN/∞✓✓NaN/∞·✓✓·
Softmax and lossesmaeLossfloat8 E4M3NaN/∞✓✓NaN/∞NaN/∞✓✓NaN/∞·✓✓·
Softmax and lossesmaeLossTF32✓
Softmax and losseshuberLossfloat64≤1≤1≤1≤1≤1≤1≤1≤1≤1≤1≤1≤1
Softmax and losseshuberLossfloat32≤1≤1≤1≤1≤1≤1≤1≤1≤1≤1≤1≤1
Softmax and losseshuberLossbfloat16≤1≤1≤1≤1≤1≤1≤1≤1≤1rejectsrejects≤1
Softmax and losseshuberLossfloat16NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞≤1NaN/∞NaN/∞
Softmax and losseshuberLossfloat8 E5M2NaN/∞✓✓NaN/∞NaN/∞✓✓NaN/∞·✓✓·
Softmax and losseshuberLossfloat8 E4M3NaN/∞✓✓NaN/∞NaN/∞✓✓NaN/∞·✓✓·
Softmax and losseshuberLossTF32≤1
Softmax and losseshingeLossfloat64✓✓✓✓✓✓✓✓✓✓✓✓
Softmax and losseshingeLossfloat32✓✓✓✓✓✓✓✓✓✓✓✓
Softmax and losseshingeLossbfloat16✓✓✓✓✓✓✓✓✓rejects✓✓
Softmax and losseshingeLossfloat16✓✓✓✓✓✓✓✓✓✓✓✓
Softmax and losseshingeLossfloat8 E5M2✓✓✓✓✓✓✓✓·≤1≤1·
Softmax and losseshingeLossfloat8 E4M3✓✓✓✓✓✓✓✓·✓✓·
Softmax and losseshingeLossTF32✓
Softmax and lossespoissonLossfloat64≤1≤1≤14≤14≤1≤1≤14≤13,993,944,752
Softmax and lossespoissonLossfloat32≤1≤12≤12≤1✓4✓≤1✓8
Softmax and lossespoissonLossbfloat16244444424rejects42
Softmax and lossespoissonLossfloat16NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞✓NaN/∞NaN/∞
Softmax and lossespoissonLossfloat8 E5M2NaN/∞✓✓NaN/∞NaN/∞✓✓NaN/∞·≤1≤1·
Softmax and lossespoissonLossfloat8 E4M3✓convconv✓4✓✓✓·convconv·
Softmax and lossespoissonLossTF323
Softmax and losseslogCoshLossfloat64≤1NaN/∞NaN/∞664,476,679,601,556,291,5844,476,679,601,556,291,584NaN/∞NaN/∞rejectsrejects4,476,679,601,556,291,584
Softmax and losseslogCoshLossfloat32≤1NaN/∞NaN/∞55≤19NaN/∞NaN/∞NaN/∞rejects≤1
Softmax and losseslogCoshLossbfloat16✓NaN/∞NaN/∞14101010NaN/∞NaN/∞rejectsrejects14
Softmax and losseslogCoshLossfloat16NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞rejectsNaN/∞
Softmax and losseslogCoshLossfloat8 E5M2NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞✓✓NaN/∞·NaN/∞rejects·
Softmax and losseslogCoshLossfloat8 E4M3NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞✓✓NaN/∞·NaN/∞rejects·
Softmax and losseslogCoshLossTF32✓
Softmax and lossescosineLossfloat64≤13333334,372,995,238,176,751,6164,372,995,238,176,751,6164,372,995,238,176,751,6164,372,995,238,176,751,6164,372,995,238,176,751,616
Softmax and lossescosineLossfloat32✓864,026,624864,026,624864,026,624864,026,624864,026,624872,415,232≤1≤1≤1≤1≤1
Softmax and lossescosineLossbfloat16≤115,36015,36015,42415,42415,42415,42415,10415,104rejectsrejects15,232
Softmax and lossescosineLossfloat16≤115,36015,36015,36015,36015,36015,360NaN/∞NaN/∞✓NaN/∞NaN/∞
Softmax and lossescosineLossfloat8 E5M2✓✓✓6060✓✓NaN/∞·✓✓·
Softmax and lossescosineLossfloat8 E4M3✓✓✓33✓✓4·✓✓·
Softmax and lossescosineLossTF32≤1
Softmax and lossesdistillfloat64✓✓✓≤1✓✓✓✓✓✓3,356,1943,714,349
Softmax and lossesdistillfloat32≤1≤1✓✓✓✓✓✓✓✓✓✓
Softmax and lossesdistillbfloat16≤1✓✓✓✓✓✓✓✓rejectsrejects✓
Softmax and lossesdistillfloat16≤1✓✓✓✓≤1✓✓✓✓✓✓
Softmax and lossesdistillfloat8 E5M2✓✓✓≤1≤1✓✓≤1·✓✓·
Softmax and lossesdistillfloat8 E4M3✓✓✓NaN/∞NaN/∞✓✓✓·✓✓·
Softmax and lossesdistillTF32≤1
Layerslinearfloat64≤1≤1≤1≤1≤1≤1≤1≤1≤1≤1≤1rejects
Layerslinearfloat32≤1≤1≤1≤1≤1≤16,552≤1≤1≤16,552≤1
Layerslinearbfloat1616,256✓✓16,25616,25664016,256✓16,256rejects✓rejects
Layerslinearfloat1615,360✓≤115,36015,36015,36015,36015,36015,360✓✓rejects
Layerslinearfloat8 E5M260✓✓6060✓✓✓·≤1≤1·
Layerslinearfloat8 E4M3≤1✓✓≤1≤1✓✓✓·✓✓·
LayerslinearTF32130,048
Layersmatmulfloat64≤1≤1≤1≤1≤1≤1≤1≤1≤1≤1≤1≤1
Layersmatmulfloat32≤1≤1≤1≤1≤1≤18,388,608≤1≤1≤18,388,608≤1
Layersmatmulbfloat16≤1✓✓✓✓≤1✓✓✓rejects✓✓
Layersmatmulfloat16NaN/∞✓✓✓✓✓✓✓✓✓✓✓
Layersmatmulfloat8 E5M2NaN/∞✓✓✓≤1✓✓✓·≤1≤1·
Layersmatmulfloat8 E4M3NaN/∞convconv✓NaN/∞✓✓✓·convconv·
LayersmatmulTF32✓
LayersscaledMatmulfloat64≤1≤1≤1≤1≤1≤1≤1≤1≤1≤1≤1≤1
LayersscaledMatmulfloat32≤1≤1≤1≤1≤1≤18,388,608≤1≤1≤18,388,608≤1
LayersscaledMatmulbfloat16≤1✓✓✓✓≤1✓✓✓rejects✓✓
LayersscaledMatmulfloat16≤1≤1≤1≤1≤1≤1≤1≤1≤1✓≤1≤1
LayersscaledMatmulfloat8 E5M2≤1✓✓≤14✓✓✓·≤1≤1·
LayersscaledMatmulfloat8 E4M3NaN/∞convconv≤1NaN/∞✓✓✓·convconv·
LayersscaledMatmulTF32≤1
Layerscontractfloat64≤1≤1≤1≤1≤1≤1≤1≤1≤1≤1≤1≤1
Layerscontractfloat32≤1≤1≤1≤1≤1≤12,848≤1≤1≤12,848≤1
Layerscontractbfloat16≤1✓✓✓✓≤1✓✓✓rejectsrejects✓
Layerscontractfloat16✓✓✓✓✓✓✓✓✓✓✓✓
Layerscontractfloat8 E5M2≤1✓✓✓✓✓✓✓·✓✓·
Layerscontractfloat8 E4M3≤1✓✓✓✓✓✓✓·✓✓·
LayerscontractTF32✓
Layersconvfloat642322222237,449rejects21,431,655,766
Layersconvfloat322222225,462237,449222
Layersconvbfloat162✓≤1≤1≤1≤1≤1≤111,410rejects≤1≤1
Layersconvfloat162✓≤1≤1≤1≤1≤1≤17,314✓≤1≤1
Layersconvfloat8 E5M22✓✓≤1✓✓✓≤1·✓✓·
Layersconvfloat8 E4M33✓✓≤1✓✓✓≤1·✓✓·
LayersconvTF322
LayersconvTransposefloat64≤1≤1≤1≤1≤1≤1≤1≤11,170rejects≤1rejects
LayersconvTransposefloat32≤1≤1≤1≤1≤1≤15,461≤17,022≤1≤1≤1
LayersconvTransposebfloat16✓✓✓✓✓✓✓✓✓rejectsrejects✓
LayersconvTransposefloat16✓✓✓✓✓✓✓✓✓✓✓✓
LayersconvTransposefloat8 E5M2✓✓✓✓✓✓✓✓·✓✓·
LayersconvTransposefloat8 E4M3✓✓✓✓✓✓✓✓·✓✓·
LayersconvTransposeTF32✓
Layerspoolfloat64≤1≤1≤1≤1≤1≤1≤1≤1≤1✓≤1≤1
Layerspoolfloat32✓✓✓≤1≤1✓≤1✓✓✓≤1≤1
Layerspoolbfloat16≤1✓✓≤1✓≤1✓≤1✓rejects✓≤1
Layerspoolfloat16NaN/∞✓✓NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞NaN/∞✓✓NaN/∞
Layerspoolfloat8 E5M2NaN/∞✓✓NaN/∞NaN/∞✓✓NaN/∞·≤1≤1·
Layerspoolfloat8 E4M3≤1✓✓≤1≤1✓✓≤1·conv✓·
LayerspoolTF32≤1
LayerssmoothMaxPoolfloat64✓✓✓✓✓✓✓✓✓✓✓15,062,304
LayerssmoothMaxPoolfloat32✓✓✓≤1✓✓✓✓✓✓✓✓
LayerssmoothMaxPoolbfloat16✓✓✓✓✓✓✓✓✓rejectsrejects✓
LayerssmoothMaxPoolfloat16✓✓✓✓✓✓✓✓✓✓✓✓
LayerssmoothMaxPoolfloat8 E5M2✓✓✓✓✓✓✓✓·✓✓·
LayerssmoothMaxPoolfloat8 E4M3NaN/∞✓✓NaN/∞NaN/∞✓✓NaN/∞·✓✓·
LayerssmoothMaxPoolTF32✓
LayerslayerNormfloat64222221,651,2921,651,2922270,268,3391,861,942,842906,188,420
LayerslayerNormfloat3222287,933,15887,933,1561,973,5431,973,54322232
LayerslayerNormbfloat16≤115,776✓≤1≤116,25616,256≤1✓✓✓≤1
LayerslayerNormfloat1636,656✓NaN/∞NaN/∞NaN/∞NaN/∞≤1≤1✓✓≤1
LayerslayerNormfloat8 E5M2≤1✓✓NaN/∞NaN/∞223·✓✓·
LayerslayerNormfloat8 E4M3≤1✓✓3≤1✓✓≤1·✓✓·
LayerslayerNormTF323
LayersbatchNormfloat642≤1≤1≤1≤169,60269,602≤1≤169,602rejects≤1
LayersbatchNormfloat32≤1≤1277,645,02277,645,0219,4959,495229,495rejects2
LayersbatchNormbfloat16✓✓✓✓✓15,82115,821✓✓rejectsrejects✓
LayersbatchNormfloat16≤1✓✓NaN/∞NaN/∞NaN/∞NaN/∞✓✓410rejects✓
LayersbatchNormfloat8 E5M2✓✓✓NaN/∞NaN/∞22≤1·2rejects·
LayersbatchNormfloat8 E4M3≤1rejectsrejects≤1✓✓✓✓·✓rejects·
LayersbatchNormTF32≤1
LayersbatchNormRunningfloat64≤1≤1≤1≤1≤1≤1≤1≤1≤160,902,52960,902,529≤1
LayersbatchNormRunningfloat32≤1≤12≤1≤1≤1≤1≤1≤1≤12≤1
LayersbatchNormRunningbfloat16≤1✓✓✓✓≤1≤1≤1≤1rejectsrejects≤1
LayersbatchNormRunningfloat16✓✓✓✓✓✓✓✓✓✓✓✓
LayersbatchNormRunningfloat8 E5M2✓✓✓✓✓✓✓✓·≤1≤1·
LayersbatchNormRunningfloat8 E4M3✓✓✓✓✓✓✓✓·✓✓·
LayersbatchNormRunningTF32≤1
Layersembeddingfloat64✓✓✓✓✓✓✓✓✓✓✓✓
Layersembeddingfloat32✓✓✓✓✓✓✓✓✓✓✓✓
Layersembeddingbfloat16✓✓✓✓✓✓✓✓✓✓✓✓
Layersembeddingfloat16✓✓✓✓✓✓✓✓✓✓✓✓
Layersembeddingfloat8 E5M2✓✓✓✓✓✓✓✓·≤1≤1·
Layersembeddingfloat8 E4M3✓✓✓✓✓✓✓✓·✓✓·
LayersembeddingTF32✓
Layersdropoutfloat64randrandrandrandrandrandrandrandrandrandrandrand
Layersdropoutfloat32randrandrandrandrandrandrandrandrandrandrandrand
Layersdropoutbfloat16randrandrandrandrandrandrandrandrandrandrandrand
Layersdropoutfloat16randrandrandrandrandrandrandrandrandrandrandrand
Layersdropoutfloat8 E5M2randrandrandrandrandrandrandrand·randrand·
Layersdropoutfloat8 E4M3randrandrandrandrandrandrandrand·randrand·
LayersdropoutTF32rand
Attention, scans and transformsattentionfloat64≤122442,878,341453,268,174≤1≤1≤1≤1232,310,360rejects329,441,711
Attention, scans and transformsattentionfloat32≤1≤12≤1≤1≤17,517≤1≤1≤1≤1≤1
Attention, scans and transformsattentionbfloat162✓✓≤1≤1≤1≤1✓≤1rejects≤1≤1
Attention, scans and transformsattentionfloat16≤1✓✓≤1≤12≤1≤1≤1≤1≤1≤1
Attention, scans and transformsattentionfloat8 E5M2≤1✓✓✓✓✓✓✓·✓✓·
Attention, scans and transformsattentionfloat8 E4M3≤1✓✓✓✓✓✓✓·✓✓·
Attention, scans and transformsattentionTF32≤1
Attention, scans and transformsattnFromScoresfloat64≤1≤1≤1≤1≤1≤1≤1≤1≤1≤1786,302,818206,740,675
Attention, scans and transformsattnFromScoresfloat32≤1≤12≤12≤12,857≤12≤12,857≤1
Attention, scans and transformsattnFromScoresbfloat16≤1≤1≤1≤1≤1≤1≤1≤1≤1rejects≤1≤1
Attention, scans and transformsattnFromScoresfloat16≤1✓✓≤1≤1≤1✓≤1≤1✓✓≤1
Attention, scans and transformsattnFromScoresfloat8 E5M2≤1✓✓≤1≤1✓✓≤1·✓✓·
Attention, scans and transformsattnFromScoresfloat8 E4M3✓✓✓NaN/∞✓✓✓NaN/∞·✓✓·
Attention, scans and transformsattnFromScoresTF32≤1
Attention, scans and transformsmultiheadAttnfloat641,0241,0241,024596,314,433933,134,2411,0231,0241,0241,0241,300,955,194rejects1,022,160,305
Attention, scans and transformsmultiheadAttnfloat321,0241,0241,0241,0241,0241,02441,317,0671,0231,0241,02441,317,0671,023
Attention, scans and transformsmultiheadAttnbfloat16396≤1≤1≤1≤13≤1✓≤1rejects≤12
Attention, scans and transformsmultiheadAttnfloat162,965≤1≤1≤1232332≤12
Attention, scans and transformsmultiheadAttnfloat8 E5M277✓✓✓✓✓✓✓·✓✓·
Attention, scans and transformsmultiheadAttnfloat8 E4M317✓✓✓✓✓✓✓·✓✓·
Attention, scans and transformsmultiheadAttnTF325,043
Attention, scans and transformsselectiveScanfloat64≤1≤1≤1≤1≤1≤1≤1≤1≤1≤1≤1≤1
Attention, scans and transformsselectiveScanfloat32≤1≤1≤1≤1≤1≤1≤1≤1≤1≤1≤1≤1
Attention, scans and transformsselectiveScanbfloat16≤1≤1≤1≤1≤1≤1≤1≤1≤1rejects≤1≤1
Attention, scans and transformsselectiveScanfloat16≤1≤1≤1≤1≤1≤1≤1≤1≤1≤1≤1≤1
Attention, scans and transformsselectiveScanfloat8 E5M2≤1✓✓≤1≤1✓✓≤1·✓✓·
Attention, scans and transformsselectiveScanfloat8 E4M3✓✓✓✓✓✓✓✓·✓✓·
Attention, scans and transformsselectiveScanTF32≤1
Attention, scans and transformsrfftfloat6453≤1≤1≤1≤1≤1≤1≤14,433,512,358,169,542,656rejects463,817,785
Attention, scans and transformsrfftfloat3211≤1≤12≤1≤1≤1✓≤1986,185,728rejects≤1
Attention, scans and transformsrfftbfloat167✓✓✓✓✓✓✓✓15,016rejects✓
Attention, scans and transformsrfftfloat168✓✓✓✓✓✓✓✓5,952rejects✓
Attention, scans and transformsrfftfloat8 E5M28✓✓✓✓✓✓✓·21rejects·
Attention, scans and transformsrfftfloat8 E4M310✓✓✓✓✓✓✓·✓rejects·
Attention, scans and transformsrfftTF328
Attention, scans and transformsirfftfloat644≤1≤1≤1≤1≤1≤1≤1≤14,370,293,078,494,281,728rejects852,222,391
Attention, scans and transformsirfftfloat32432222222873,254,093rejects2
Attention, scans and transformsirfftbfloat162✓✓✓✓✓✓✓✓13,286rejects✓
Attention, scans and transformsirfftfloat1613✓✓✓✓✓✓✓✓3rejects✓
Attention, scans and transformsirfftfloat8 E5M251✓✓✓✓✓✓✓·±0rejects·
Attention, scans and transformsirfftfloat8 E4M354✓✓✓✓✓✓✓·±0rejects·
Attention, scans and transformsirfftTF3213
Movement and indexingdetachfloat64✓✓✓✓✓✓✓·✓✓✓✓
Movement and indexingdetachfloat32✓✓✓✓✓✓✓·✓✓✓✓
Movement and indexingdetachbfloat16✓✓✓✓✓✓✓·✓✓✓✓
Movement and indexingdetachfloat16✓✓✓✓✓✓✓·✓✓✓✓
Movement and indexingdetachfloat8 E5M2✓✓✓✓✓✓✓·rejects✓✓rejects
Movement and indexingdetachfloat8 E4M3✓✓✓✓✓✓✓·rejects✓✓rejects
Movement and indexingdetachTF32✓
Movement and indexingreshapefloat64✓✓✓✓✓✓✓✓✓✓✓✓
Movement and indexingreshapefloat32✓✓✓✓✓✓✓✓✓✓✓✓
Movement and indexingreshapebfloat16✓✓✓✓✓✓✓✓✓✓✓✓
Movement and indexingreshapefloat16✓✓✓✓✓✓✓✓✓✓✓✓
Movement and indexingreshapefloat8 E5M2✓✓✓✓✓✓✓✓·✓✓·
Movement and indexingreshapefloat8 E4M3✓✓✓✓✓✓✓✓·✓✓·
Movement and indexingreshapeTF32✓
Movement and indexingpermutefloat64✓✓✓✓✓✓✓✓✓✓✓✓
Movement and indexingpermutefloat32✓✓✓✓✓✓✓✓✓✓✓✓
Movement and indexingpermutebfloat16✓✓✓✓✓✓✓✓✓✓✓✓
Movement and indexingpermutefloat16✓✓✓✓✓✓✓✓✓✓✓✓
Movement and indexingpermutefloat8 E5M2✓✓✓✓✓✓✓✓·✓≤1·
Movement and indexingpermutefloat8 E4M3✓✓✓✓✓✓✓✓·✓✓·
Movement and indexingpermuteTF32✓
Movement and indexingbroadcastfloat64✓✓✓✓✓✓✓✓✓✓✓✓
Movement and indexingbroadcastfloat32✓✓✓✓✓✓✓✓✓✓✓✓
Movement and indexingbroadcastbfloat16✓✓✓✓✓✓✓✓✓rejects✓✓
Movement and indexingbroadcastfloat16✓✓✓✓✓✓✓✓✓✓✓✓
Movement and indexingbroadcastfloat8 E5M2✓✓✓✓✓✓✓✓·≤1≤1·
Movement and indexingbroadcastfloat8 E4M3✓✓✓✓✓✓✓✓·✓✓·
Movement and indexingbroadcastTF32✓
Movement and indexingfullLikefloat64✓✓✓✓✓✓✓✓✓✓✓✓
Movement and indexingfullLikefloat32✓✓✓✓✓✓✓✓✓✓✓✓
Movement and indexingfullLikebfloat16✓✓✓✓✓✓✓✓✓rejects✓✓
Movement and indexingfullLikefloat16✓✓✓✓✓✓✓✓✓✓✓✓
Movement and indexingfullLikefloat8 E5M2✓✓✓✓✓✓✓✓·≤1≤1·
Movement and indexingfullLikefloat8 E4M3✓✓✓✓✓✓✓✓·✓✓·
Movement and indexingfullLikeTF32✓
Movement and indexingflipfloat64✓✓✓✓✓✓✓✓✓✓✓✓
Movement and indexingflipfloat32✓✓✓✓✓✓✓✓✓✓✓✓
Movement and indexingflipbfloat16✓✓✓✓✓✓✓✓✓✓✓✓
Movement and indexingflipfloat16✓✓✓✓✓✓✓✓✓✓✓✓
Movement and indexingflipfloat8 E5M2✓✓✓✓✓✓✓✓·≤1≤1·
Movement and indexingflipfloat8 E4M3✓✓✓✓✓✓✓✓·✓✓·
Movement and indexingflipTF32✓
Movement and indexingslicefloat64✓✓✓✓✓✓✓✓✓✓✓✓
Movement and indexingslicefloat32✓✓✓✓✓✓✓✓✓✓✓✓
Movement and indexingslicebfloat16✓✓✓✓✓✓✓✓✓✓✓✓
Movement and indexingslicefloat16✓✓✓✓✓✓✓✓✓✓✓✓
Movement and indexingslicefloat8 E5M2✓✓✓✓✓✓✓✓·≤1≤1·
Movement and indexingslicefloat8 E4M3✓✓✓✓✓✓✓✓·✓✓·
Movement and indexingsliceTF32✓
Movement and indexingpadfloat64✓✓✓✓✓✓✓✓✓✓✓✓
Movement and indexingpadfloat32✓✓✓✓✓✓✓✓✓✓✓✓
Movement and indexingpadbfloat16✓✓✓✓✓✓✓✓✓rejects✓✓
Movement and indexingpadfloat16✓✓✓✓✓✓✓✓✓✓✓✓
Movement and indexingpadfloat8 E5M2✓✓✓✓✓✓✓✓·≤1≤1·
Movement and indexingpadfloat8 E4M3✓✓✓✓✓✓✓✓·✓✓·
Movement and indexingpadTF32✓
Movement and indexingcatfloat64✓✓✓✓✓✓✓✓✓✓✓✓
Movement and indexingcatfloat32✓✓✓✓✓✓✓✓✓✓✓✓
Movement and indexingcatbfloat16✓✓✓✓✓✓✓✓✓✓✓✓
Movement and indexingcatfloat16✓✓✓✓✓✓✓✓✓✓✓✓
Movement and indexingcatfloat8 E5M2✓✓✓✓✓✓✓✓·≤1≤1·
Movement and indexingcatfloat8 E4M3✓✓✓✓✓✓✓✓·✓✓·
Movement and indexingcatTF32✓
Movement and indexinggatherfloat64✓✓✓✓✓✓✓✓✓✓✓✓
Movement and indexinggatherfloat32✓✓✓✓✓✓✓✓✓✓✓✓
Movement and indexinggatherbfloat16✓✓✓✓✓✓✓✓✓✓✓✓
Movement and indexinggatherfloat16✓✓✓✓✓✓✓✓✓✓✓✓
Movement and indexinggatherfloat8 E5M2✓✓✓✓✓✓✓✓·✓✓·
Movement and indexinggatherfloat8 E4M3✓✓✓✓✓✓✓✓·✓✓·
Movement and indexinggatherTF32✓
Movement and indexingscatterfloat64≤1≤14,503,599,627,370,496≤1≤1≤14,503,599,627,370,496≤14,503,599,627,370,496≤14,503,599,627,370,496≤1
Movement and indexingscatterfloat32✓✓8,388,608✓8,388,608✓8,388,608✓8,388,608✓8,388,608✓
Movement and indexingscatterbfloat16✓✓128✓✓✓✓✓128✓128✓
Movement and indexingscatterfloat16≤1✓1,024≤1≤1≤1≤1≤11,024✓1,024≤1
Movement and indexingscatterfloat8 E5M2✓✓4✓✓✓4✓·≤14·
Movement and indexingscatterfloat8 E4M3✓✓8✓✓✓8✓·✓8·
Movement and indexingscatterTF32≤1
Movement and indexingindexAtfloat64✓✓✓✓✓✓✓✓✓✓✓✓
Movement and indexingindexAtfloat32✓✓✓✓✓✓✓✓✓✓✓✓
Movement and indexingindexAtbfloat16✓✓✓✓✓✓✓✓✓✓✓✓
Movement and indexingindexAtfloat16✓✓✓✓✓✓✓✓✓✓✓✓
Movement and indexingindexAtfloat8 E5M2✓✓✓✓✓✓✓✓·≤1≤1·
Movement and indexingindexAtfloat8 E4M3✓✓✓✓✓✓✓✓·✓✓·
Movement and indexingindexAtTF32✓
Movement and indexingindicesfloat64✓✓✓✓✓✓✓✓✓✓✓✓
Movement and indexingindicesfloat32✓✓✓✓✓✓✓✓✓✓✓✓
Movement and indexingindicesbfloat16✓✓✓✓✓✓✓✓✓✓✓✓
Movement and indexingindicesfloat16✓✓✓✓✓✓✓✓✓✓✓✓
Movement and indexingindicesfloat8 E5M2✓✓✓✓✓✓✓✓·✓✓·
Movement and indexingindicesfloat8 E4M3✓✓✓✓✓✓✓✓·✓✓·
Movement and indexingindicesTF32✓
Movement and indexingencodeIndexfloat64✓···········
Movement and indexingencodeIndexfloat32✓···········
Movement and indexingencodeIndexbfloat16✓···········
Movement and indexingencodeIndexfloat16✓···········
Movement and indexingencodeIndexfloat8 E5M2✓···········
Movement and indexingencodeIndexfloat8 E4M3✓···········
Movement and indexingencodeIndexTF32✓
Movement and indexingdecodeIndexfloat64✓···········
Movement and indexingdecodeIndexfloat32✓···········
Movement and indexingdecodeIndexbfloat16✓···········
Movement and indexingdecodeIndexfloat16✓···········
Movement and indexingdecodeIndexfloat8 E5M2✓···········
Movement and indexingdecodeIndexfloat8 E4M3✓···········
Movement and indexingdecodeIndexTF32✓
Movement and indexingcastfloat64✓✓✓✓✓✓✓✓✓✓✓✓
Movement and indexingcastfloat32✓✓✓8,381,831✓✓✓✓8,388,608✓✓✓
Movement and indexingcastbfloat16✓✓✓✓✓≤1≤1≤1≤1≤1≤1≤1
Movement and indexingcastfloat16✓✓✓✓✓✓✓✓✓✓✓✓
Movement and indexingcastfloat8 E5M2✓✓✓✓✓✓✓✓rejectsNaN/∞✓rejects
Movement and indexingcastfloat8 E4M3✓convconv✓✓✓✓✓rejectsconvconvrejects
Movement and indexingcastTF32✓
Movement and indexingbitcastfloat64✓✓✓✓✓✓✓✓✓✓rejects✓
Movement and indexingbitcastfloat32✓✓✓✓✓✓✓✓✓✓rejects✓
Movement and indexingbitcastbfloat16✓✓✓✓✓✓✓✓✓✓rejects✓
Movement and indexingbitcastfloat16✓✓✓✓✓✓✓✓✓✓rejects✓
Movement and indexingbitcastfloat8 E5M2✓✓✓✓✓rejectsrejects✓·rejectsrejects·
Movement and indexingbitcastfloat8 E4M3✓✓✓✓✓rejectsrejects✓·rejectsrejects·
Movement and indexingbitcastTF32✓
Logic, bits and integerslogicalNotfloat64✓✓✓✓✓✓✓✓✓✓✓✓
Logic, bits and integerslogicalNotfloat32✓✓✓✓✓✓✓✓✓✓✓✓
Logic, bits and integerslogicalNotbfloat16✓✓✓✓✓✓✓✓✓✓✓✓
Logic, bits and integerslogicalNotfloat16✓✓✓✓✓✓✓✓✓✓✓✓
Logic, bits and integerslogicalNotfloat8 E5M2✓✓✓✓✓✓✓✓·✓✓·
Logic, bits and integerslogicalNotfloat8 E4M3✓✓✓✓✓✓✓✓·✓✓·
Logic, bits and integerslogicalNotTF32✓
Logic, bits and integerslogicalAndfloat64✓✓✓✓✓✓✓✓✓✓✓✓
Logic, bits and integerslogicalAndfloat32✓✓✓✓✓✓✓✓✓✓✓✓
Logic, bits and integerslogicalAndbfloat16✓✓✓✓✓✓✓✓✓✓✓✓
Logic, bits and integerslogicalAndfloat16✓✓✓✓✓✓✓✓✓✓✓✓
Logic, bits and integerslogicalAndfloat8 E5M2✓✓✓✓✓✓✓✓·✓✓·
Logic, bits and integerslogicalAndfloat8 E4M3✓✓✓✓✓✓✓✓·✓✓·
Logic, bits and integerslogicalAndTF32✓
Logic, bits and integerslogicalOrfloat64✓✓✓✓✓✓✓✓✓✓✓✓
Logic, bits and integerslogicalOrfloat32✓✓✓✓✓✓✓✓✓✓✓✓
Logic, bits and integerslogicalOrbfloat16✓✓✓✓✓✓✓✓✓✓✓✓
Logic, bits and integerslogicalOrfloat16✓✓✓✓✓✓✓✓✓✓✓✓
Logic, bits and integerslogicalOrfloat8 E5M2✓✓✓✓✓✓✓✓·✓✓·
Logic, bits and integerslogicalOrfloat8 E4M3✓✓✓✓✓✓✓✓·✓✓·
Logic, bits and integerslogicalOrTF32✓
Logic, bits and integerslogicalXorfloat64✓✓✓✓✓✓✓✓✓✓✓0
Logic, bits and integerslogicalXorfloat32✓✓✓✓✓✓✓✓✓✓✓0
Logic, bits and integerslogicalXorbfloat16✓✓✓✓✓✓✓✓✓✓✓0
Logic, bits and integerslogicalXorfloat16✓✓✓✓✓✓✓✓✓✓✓0
Logic, bits and integerslogicalXorfloat8 E5M2✓✓✓✓✓✓✓✓·✓✓·
Logic, bits and integerslogicalXorfloat8 E4M3✓✓✓✓✓✓✓✓·✓✓·
Logic, bits and integerslogicalXorTF32✓
Logic, bits and integersbitwiseAndfloat64✓✓✓✓✓✓✓✓✓✓rejects✓
Logic, bits and integersbitwiseAndfloat32✓✓✓✓✓✓✓✓✓✓rejects✓
Logic, bits and integersbitwiseAndbfloat16✓✓✓✓✓✓✓✓✓✓rejects✓
Logic, bits and integersbitwiseAndfloat16✓✓✓✓✓✓✓✓✓✓rejects✓
Logic, bits and integersbitwiseAndfloat8 E5M2✓✓✓✓✓✓✓✓·✓rejects·
Logic, bits and integersbitwiseAndfloat8 E4M3✓✓✓✓✓✓✓✓·✓rejects·
Logic, bits and integersbitwiseAndTF32✓
Logic, bits and integersbitwiseOrfloat64✓✓✓✓✓✓✓✓✓✓rejects✓
Logic, bits and integersbitwiseOrfloat32✓✓✓✓✓✓✓✓✓✓rejects✓
Logic, bits and integersbitwiseOrbfloat16✓✓✓✓✓✓✓✓✓✓rejects✓
Logic, bits and integersbitwiseOrfloat16✓✓✓✓✓✓✓✓✓✓rejects✓
Logic, bits and integersbitwiseOrfloat8 E5M2✓✓✓✓✓✓✓✓·✓rejects·
Logic, bits and integersbitwiseOrfloat8 E4M3✓✓✓✓✓✓✓✓·✓rejects·
Logic, bits and integersbitwiseOrTF32✓
Logic, bits and integersbitwiseXorfloat64✓✓✓✓✓✓✓✓✓✓rejects✓
Logic, bits and integersbitwiseXorfloat32✓✓✓✓✓✓✓✓✓✓rejects✓
Logic, bits and integersbitwiseXorbfloat16✓✓✓✓✓✓✓✓✓✓rejects✓
Logic, bits and integersbitwiseXorfloat16✓✓✓✓✓✓✓✓✓✓rejects✓
Logic, bits and integersbitwiseXorfloat8 E5M2✓✓✓✓✓✓✓✓·✓rejects·
Logic, bits and integersbitwiseXorfloat8 E4M3✓✓✓✓✓✓✓✓·✓rejects·
Logic, bits and integersbitwiseXorTF32✓
Logic, bits and integersbitwiseNotfloat64✓✓✓✓✓✓✓✓✓✓rejects✓
Logic, bits and integersbitwiseNotfloat32✓✓✓✓✓✓✓✓✓✓rejects✓
Logic, bits and integersbitwiseNotbfloat16✓✓✓✓✓✓✓✓✓✓rejects✓
Logic, bits and integersbitwiseNotfloat16✓✓✓✓✓✓✓✓✓✓rejects✓
Logic, bits and integersbitwiseNotfloat8 E5M2✓✓✓✓✓✓✓✓·✓rejects·
Logic, bits and integersbitwiseNotfloat8 E4M3✓✓✓✓✓✓✓✓·✓rejects·
Logic, bits and integersbitwiseNotTF32✓
Logic, bits and integersbitwiseLeftShiftfloat64✓✓✓✓✓✓✓✓✓✓rejects✓
Logic, bits and integersbitwiseLeftShiftfloat32✓✓✓✓✓✓✓✓✓✓rejects✓
Logic, bits and integersbitwiseLeftShiftbfloat16✓✓✓✓✓✓✓✓✓✓rejects✓
Logic, bits and integersbitwiseLeftShiftfloat16✓✓✓✓✓✓✓✓✓✓rejects✓
Logic, bits and integersbitwiseLeftShiftfloat8 E5M2✓✓✓✓✓✓✓✓·✓rejects·
Logic, bits and integersbitwiseLeftShiftfloat8 E4M3✓✓✓✓✓✓✓✓·✓rejects·
Logic, bits and integersbitwiseLeftShiftTF32✓
Logic, bits and integersshiftRightArithfloat64✓✓✓✓✓✓✓✓✓··✓
Logic, bits and integersshiftRightArithfloat32✓✓✓✓✓✓✓✓✓··✓
Logic, bits and integersshiftRightArithbfloat16✓✓✓✓✓✓✓✓✓··✓
Logic, bits and integersshiftRightArithfloat16✓✓✓✓✓✓✓✓✓··✓
Logic, bits and integersshiftRightArithfloat8 E5M2✓✓✓✓✓✓✓✓····
Logic, bits and integersshiftRightArithfloat8 E4M3✓✓✓✓✓✓✓✓····
Logic, bits and integersshiftRightArithTF32✓
Logic, bits and integersshiftRightLogicalfloat64✓✓✓✓✓0✓✓✓✓rejects✓
Logic, bits and integersshiftRightLogicalfloat32✓✓✓✓✓0✓✓✓✓rejects✓
Logic, bits and integersshiftRightLogicalbfloat16✓✓✓✓✓0✓✓✓✓rejects✓
Logic, bits and integersshiftRightLogicalfloat16✓✓✓✓✓0✓✓✓✓rejects✓
Logic, bits and integersshiftRightLogicalfloat8 E5M2✓✓✓✓✓0✓✓·✓rejects·
Logic, bits and integersshiftRightLogicalfloat8 E4M3✓✓✓✓✓0✓✓·✓rejects·
Logic, bits and integersshiftRightLogicalTF32✓
Logic, bits and integerspopulationCountfloat64✓··✓✓✓✓✓✓···
Logic, bits and integerspopulationCountfloat32✓··✓✓✓✓✓✓···
Logic, bits and integerspopulationCountbfloat16✓··✓✓✓✓✓✓···
Logic, bits and integerspopulationCountfloat16✓··✓✓✓✓✓✓···
Logic, bits and integerspopulationCountfloat8 E5M2✓··✓✓✓✓✓····
Logic, bits and integerspopulationCountfloat8 E4M3✓··✓✓✓✓✓····
Logic, bits and integerspopulationCountTF32✓
Logic, bits and integerscountLeadZerosfloat64✓··✓✓·······
Logic, bits and integerscountLeadZerosfloat32✓··✓✓·······
Logic, bits and integerscountLeadZerosbfloat16✓··✓✓·······
Logic, bits and integerscountLeadZerosfloat16✓··✓✓·······
Logic, bits and integerscountLeadZerosfloat8 E5M2✓··✓✓·······
Logic, bits and integerscountLeadZerosfloat8 E4M3✓··✓✓·······
Logic, bits and integerscountLeadZerosTF32✓
Logic, bits and integersmulhifloat64✓···········
Logic, bits and integersmulhifloat32✓···········
Logic, bits and integersmulhibfloat16✓···········
Logic, bits and integersmulhifloat16✓···········
Logic, bits and integersmulhifloat8 E5M2✓···········
Logic, bits and integersmulhifloat8 E4M3✓···········
Logic, bits and integersmulhiTF32✓
RandomrandUniformfloat64randrandrandrandrandrandrandrandrandrandrandrand
RandomrandUniformfloat32randrandrandrandrandrandrandrandrandrandrandrand
RandomrandUniformbfloat16randrandrandrandrandrandrandrandrandrandrandrand
RandomrandUniformfloat16randrandrandrandrandrandrandrandrandrandrandrand
RandomrandUniformfloat8 E5M2randrandrandrandrandrandrandrand·randrand·
RandomrandUniformfloat8 E4M3randrandrandrandrandrandrandrand·randrand·
RandomrandUniformTF32rand
Randomrandnfloat64randrandrandrandrandrandrandrandrandrandrandrand
Randomrandnfloat32randrandrandrandrandrandrandrandrandrandrandrand
Randomrandnbfloat16randrandrandrandrandrandrandrandrandrandrandrand
Randomrandnfloat16randrandrandrandrandrandrandrandrandrandrandrand
Randomrandnfloat8 E5M2randrandrandrandrandrandrandrand·randrand·
Randomrandnfloat8 E4M3randrandrandrandrandrandrandrand·randrand·
RandomrandnTF32rand
RandombernoulliMaskfloat64randrandrandrandrandrandrandrandrandrandrandrand
RandombernoulliMaskfloat32randrandrandrandrandrandrandrandrandrandrandrand
RandombernoulliMaskbfloat16randrandrandrandrandrandrandrandrandrandrandrand
RandombernoulliMaskfloat16randrandrandrandrandrandrandrandrandrandrandrand
RandombernoulliMaskfloat8 E5M2randrandrandrandrandrandrandrand·randrand·
RandombernoulliMaskfloat8 E4M3randrandrandrandrandrandrandrand·randrand·
RandombernoulliMaskTF32rand

Start with basic arithmetic. PyTorch's CPU square root was one ULP away from the correctly rounded result for 2,490 of 400,089 float64 inputs, including \(\sqrt{2}\); on the A100, it matched the reference in every tested case. JAX and TensorFlow also had float32 mismatches on the A100, while NumPy, ONNX Runtime, and MLX matched the tested reference for these operations. IEEE 754 specifies correctly rounded results for basic arithmetic such as division and square root in its standard binary formats. We also found failures near zero. Some tested JAX CPU, TensorFlow, and CuPy paths flushed float32 subnormal values (very small representable numbers) to zero; JAX and TensorFlow did so in CPU float64 as well. The format could store the values, but those computations discarded them. At the opposite end of the range, the E4M3FN cast in PyTorch saturated where TorchLean's specified rounding produced NaN.

Normalization gives another example. Standardization subtracts a mean and divides by a standard deviation. With \(\mu\) the mean of \(n\) values, these two variances are equal over the reals:

\[ \begin{aligned} v&=\frac{1}{n}\sum_i x_i^2-\mu^2\\[3pt] &=\frac{1}{n}\sum_i(x_i-\mu)^2. \end{aligned} \]

The first formula subtracts two large, nearly equal numbers. When the inputs share a large mean, rounding can erase the small variance we wanted to measure. For the float32 row \([10001,10002,10003,10004]\), the default jax.nn.standardize computation gave zero variance instead of 1.25. Its first normalized value was about \(-474.34\) rather than \(-1.342\) on both devices. The JAX documentation actually warns about this and provides algorithm="stable". PyTorch Geometric's variance aggregation showed a similar problem: \([4095,4097,4097]\) gave \(-2\) in float32 where the true variance was \(8/9\), and the subsequent standard deviation returned zero.

Now look at matrix multiplication. A matrix multiplication is a collection of dot products, and the internal precision matters just as much as the type of the output. On the A100, TensorFlow and ONNX Runtime CUDA used TF32 for float32 matrix products in the tested default paths. TF32 retains 10 fraction bits (see NVIDIA's accuracy notes), so an input of 4097 is rounded to 4096:

\[ \begin{aligned} s_{\mathbb R}&=4097-4096+1=2,\\ s_{\mathrm{TF32}}&=4096-4096+1=1. \end{aligned} \]

Disabling TF32 gave the correctly rounded result in both libraries for this example. I'd like that setting to be much easier to see. A float32 output doesn't tell us what precision the library used for the products inside it.

Let's look at an activation example. Sigmoid always has a small positive value for a finite negative input, but ONNX Runtime returned zero at \(-16.1\) in float32 on the CPU, at \(-16.6\) on the A100, and at \(-36.8\) in float64, even though the answers were representable. The tanh approximation to GELU has a related cancellation problem. Writing it as \(G(x)\):

\[ \begin{aligned} z&=\sqrt{2/\pi}\,(x+0.044715x^3),\\[3pt] G(x)&=\tfrac12 x(1+\tanh z). \end{aligned} \]

For sufficiently negative \(x\), \(\tanh z\) rounds to \(-1\), so \(1+\tanh z\) becomes zero. At \(x=-6\) in float32, PyTorch, the tested Transformers variants, JAX, and TorchLean's usual tanh GELU returned negative zero instead of about \(-8.4\times10^{-11}\). Writing the same approximation with sigmoid \(\sigma\) keeps the small value. This is an algebraic rearrangement of the tanh formula, not a switch to the erf definition:

\[ \tfrac12 x(1+\tanh z)=x\,\sigma(2z). \]

Case study I: softmax and cross-entropy

A classifier produces scores, or logits, and softmax turns them into probabilities:

\[ p_i=\frac{e^{z_i}}{\sum_j e^{z_j}}. \]

For the correct class \(t\), the cross-entropy loss and its gradient over the real numbers are:

\[ \begin{aligned} L&=-\log p_t,\\[3pt] \frac{\partial L}{\partial z_t}&=p_t-1. \end{aligned} \]

For finite logits and more than one class, the target gradient should be negative, even if it is very small. Take logits \([9,-9,-9]\), with class 0 as the target. The usual trick of subtracting the largest logit prevents overflow but still leaves this denominator:

\[ \begin{aligned} D&=1+e^{-18}+e^{-18},\\ e^{-18}&\approx1.52\times10^{-8}. \end{aligned} \]

Each small exponential is less than half the float32 spacing above 1, so adding it to 1 rounds it away. The computed target probability becomes exactly 1, and both the loss and its target gradient become zero. But the true loss is positive and the gradient negative, each with magnitude about \(3.046\times10^{-8}\). Float32 can represent these numbers; we lost them in the addition to 1. This is the Softmax Collapse phenomenon that drew me into the project. The recent softmax rewrite gives a way around it.

The repair relies on two standard numerical functions. expm1(x) computes \(e^x-1\) without first rounding \(e^x\) to 1, and log1p(x) computes \(\log(1+x)\) without losing a small \(x\) in the addition. For instance, \(e^{10^{-8}}-1\) evaluates to zero if we compute it directly in float32, while expm1 keeps a value close to \(10^{-8}\). Rather than adding the small exponentials to 1, we save their sum as \(T\) and compute:

\[ \begin{aligned} T&=e^{-18}+e^{-18},\\ L&=\operatorname{log1p}(T),\\ g_0&=\operatorname{expm1}(-L). \end{aligned} \]

For this input, the rewritten float32 target gradient is correctly rounded. In the trace below, watch the step that adds the exponentials.

Logits, target 0
Format
Show through step
Standard formula
logitsx₀9x₁−9x₂−9

logits

nodebitscomputedexacterror
x₀ = logit 00x4110000099exact
x₁ = logit 10xc1100000−9−9exact
x₂ = logit 20xc1100000−9−9exact
x − maxy₀0y₁−18y₂−18

x − max

nodebitscomputedexacterror
y₀ = x0 − max0x0000000000exact
y₁ = x1 − max0xc1900000−18−18exact
y₂ = x2 − max0xc1900000−18−18exact
expe₀1e₁1.523e−8e₂1.523e−8

exp

nodebitscomputedexacterror
e₀ = exp(y0)0x3f80000011exact
e₁ = exp(y1)0x3282d3141.5229979e−81.522998e−80.39 units in the last place
e₂ = exp(y2)0x3282d3141.5229979e−81.522998e−80.39 units in the last place
running sums₀1s₁1s₂1rounds to 1

running sum

nodebitscomputedexacterror
s₀ = 0 + e00x3f80000011exact
s₁ = s0 + e10x3f800000110.13 units in the last place
s₂ = s1 + e20x3f800000110.26 units in the last place
log of the sumlog s0

log of the sum

nodebitscomputedexacterror
log s = log(s2)0x0000000003.0459959e−80 where the exact value is not
log-prob, losslog p₀0loss−0

log-prob, loss

nodebitscomputedexacterror
log p₀ = y0 − log s0x000000000−3.0459959e−80 where the exact value is not
loss = −log p00x8000000003.0459959e−80 where the exact value is not
target gradientp₀1g₀0

target gradient

nodebitscomputedexacterror
p₀ = e0 / s20x3f80000010.999999970.51 units in the last place
g₀ = p0 − 10x000000000−3.0459959e−80 where the exact value is not

Lean's theorems check this gradient: |computed − exact| ≤ 32u·|exact| + 32η = 5.81e−14. This lane is off by 3.05e−8, outside the bound.

TorchLean
logitsx₀9x₁−9x₂−9

logits

nodebitscomputedexacterror
x₀ = logit 00x4110000099exact
x₁ = logit 10xc1100000−9−9exact
x₂ = logit 20xc1100000−9−9exact
x − x[pivot]y₀0y₁−18y₂−18

x − x[pivot]

nodebitscomputedexacterror
y₀ = x0 − max0x0000000000exact
y₁ = x1 − max0xc1900000−18−18exact
y₂ = x2 − max0xc1900000−18−18exact
exp, off the pivote₁1.523e−8e₂1.523e−8

exp, off the pivot

nodebitscomputedexacterror
e₁ = exp(y1)0x3282d3141.5229979e−81.522998e−80.39 units in the last place
e₂ = exp(y2)0x3282d3141.5229979e−81.522998e−80.39 units in the last place
tail sumt₁1.523e−8t₂3.046e−8

tail sum

nodebitscomputedexacterror
t₁ = 0 + 0 + e10x3282d3141.5229979e−81.522998e−80.39 units in the last place
t₂ = t1 + e20x3302d3143.0459958e−83.0459959e−80.39 units in the last place
log1p of the taillog1p t3.046e−8

log1p of the tail

nodebitscomputedexacterror
log1p t = log1p(t2)0x3302d3143.0459958e−83.0459959e−80.26 units in the last place
log-prob, losslog p₀−3.046e−8loss3.046e−8

log-prob, loss

nodebitscomputedexacterror
log p₀ = y0 − log s0xb302d314−3.0459958e−8−3.0459959e−80.26 units in the last place
loss = −log p00x3302d3143.0459958e−83.0459959e−80.26 units in the last place
target gradientexpm1−3.046e−8g₀−3.046e−8

target gradient

nodebitscomputedexacterror
expm1 = expm1(log p0)0xb302d314−3.0459958e−8−3.0459959e−80.13 units in the last place
g₀ = −expm1(log p0)·(−1) − p0·00xb302d314−3.0459958e−8−3.0459959e−80.13 units in the last place

Lean's theorems check this gradient: |computed − exact| ≤ 32u·|exact| + 32η = 5.81e−14. This lane is off by 4.5e−16, inside the bound.

The two small exponentials add up to 3.05e−8, less than half a unit of binary32 at 1, so the standard sum rounds to exactly 1. The standard target gradient is 0; the exact one is −3.046e−8. TorchLean's is −3.046e−8, relative error 1.5e−8.

Standard formula
logitsx₀9x₁−9x₂−9

logits

nodebitscomputedexacterror
x₀ = logit 00x411099exact
x₁ = logit 10xc110−9−9exact
x₂ = logit 20xc110−9−9exact
x − maxy₀0y₁−18y₂−18

x − max

nodebitscomputedexacterror
y₀ = x0 − max0x000000exact
y₁ = x1 − max0xc190−18−18exact
y₂ = x2 − max0xc190−18−18exact
expe₀1e₁1.525e−8e₂1.525e−8

exp

nodebitscomputedexacterror
e₀ = exp(y0)0x3f8011exact
e₁ = exp(y1)0x32831.5250407e−81.522998e−80.18 units in the last place
e₂ = exp(y2)0x32831.5250407e−81.522998e−80.18 units in the last place
running sums₀1s₁1s₂1rounds to 1

running sum

nodebitscomputedexacterror
s₀ = 0 + e00x3f8011exact
s₁ = s0 + e10x3f80111.5e−8 relative
s₂ = s1 + e20x3f80113e−8 relative
log of the sumlog s0

log of the sum

nodebitscomputedexacterror
log s = log(s2)0x000003.0459959e−80 where the exact value is not
log-prob, losslog p₀0loss−0

log-prob, loss

nodebitscomputedexacterror
log p₀ = y0 − log s0x00000−3.0459959e−80 where the exact value is not
loss = −log p00x800003.0459959e−80 where the exact value is not
target gradientp₀1g₀0

target gradient

nodebitscomputedexacterror
p₀ = e0 / s20x3f8010.999999973e−8 relative
g₀ = p0 − 10x00000−3.0459959e−80 where the exact value is not

The theorems' tolerance, 32u·|exact| + 32η, is 3.81e−9 here, computed in Python; no theorem covers this input and format. This lane is off by 3.05e−8, outside it.

TorchLean
logitsx₀9x₁−9x₂−9

logits

nodebitscomputedexacterror
x₀ = logit 00x411099exact
x₁ = logit 10xc110−9−9exact
x₂ = logit 20xc110−9−9exact
x − x[pivot]y₀0y₁−18y₂−18

x − x[pivot]

nodebitscomputedexacterror
y₀ = x0 − max0x000000exact
y₁ = x1 − max0xc190−18−18exact
y₂ = x2 − max0xc190−18−18exact
exp, off the pivote₁1.525e−8e₂1.525e−8

exp, off the pivot

nodebitscomputedexacterror
e₁ = exp(y1)0x32831.5250407e−81.522998e−80.18 units in the last place
e₂ = exp(y2)0x32831.5250407e−81.522998e−80.18 units in the last place
tail sumt₁1.525e−8t₂3.0501e−8

tail sum

nodebitscomputedexacterror
t₁ = 0 + 0 + e10x32831.5250407e−81.522998e−80.18 units in the last place
t₂ = t1 + e20x33033.0500814e−83.0459959e−80.18 units in the last place
log1p of the taillog1p t3.0501e−8

log1p of the tail

nodebitscomputedexacterror
log1p t = log1p(t2)0x33033.0500814e−83.0459959e−80.18 units in the last place
log-prob, losslog p₀−3.0501e−8loss3.0501e−8

log-prob, loss

nodebitscomputedexacterror
log p₀ = y0 − log s0xb303−3.0500814e−8−3.0459959e−80.18 units in the last place
loss = −log p00x33033.0500814e−83.0459959e−80.18 units in the last place
target gradientexpm1−3.0501e−8g₀−3.0501e−8

target gradient

nodebitscomputedexacterror
expm1 = expm1(log p0)0xb303−3.0500814e−8−3.0459959e−80.18 units in the last place
g₀ = −expm1(log p0)·(−1) − p0·00xb303−3.0500814e−8−3.0459959e−80.18 units in the last place

The theorems' tolerance, 32u·|exact| + 32η, is 3.81e−9 here, computed in Python; no theorem covers this input and format. This lane is off by 4.09e−11, inside it.

The two small exponentials add up to 3.05e−8, less than half a unit of bfloat16 at 1, so the standard sum rounds to exactly 1. The standard target gradient is 0; the exact one is −3.046e−8. TorchLean's is −3.0501e−8, relative error 0.0013.

Standard formula
logitsx₀9x₁−9x₂−9

logits

nodebitscomputedexacterror
x₀ = logit 00x488099exact
x₁ = logit 10xc880−9−9exact
x₂ = logit 20xc880−9−9exact
x − maxy₀0y₁−18y₂−18

x − max

nodebitscomputedexacterror
y₀ = x0 − max0x000000exact
y₁ = x1 − max0xcc80−18−18exact
y₂ = x2 − max0xcc80−18−18exact
expe₀1e₁0e₂0

exp

nodebitscomputedexacterror
e₀ = exp(y0)0x3c0011exact
e₁ = exp(y1)0x000001.522998e−80 where the exact value is not
e₂ = exp(y2)0x000001.522998e−80 where the exact value is not
running sums₀1s₁1s₂1rounds to 1

running sum

nodebitscomputedexacterror
s₀ = 0 + e00x3c0011exact
s₁ = s0 + e10x3c00111.5e−8 relative
s₂ = s1 + e20x3c00113e−8 relative
log of the sumlog s0

log of the sum

nodebitscomputedexacterror
log s = log(s2)0x000003.0459959e−80 where the exact value is not
log-prob, losslog p₀0loss−0

log-prob, loss

nodebitscomputedexacterror
log p₀ = y0 − log s0x00000−3.0459959e−80 where the exact value is not
loss = −log p00x800003.0459959e−80 where the exact value is not
target gradientp₀1g₀0

target gradient

nodebitscomputedexacterror
p₀ = e0 / s20x3c0010.999999973e−8 relative
g₀ = p0 − 10x00000−3.0459959e−80 where the exact value is not

The theorems' tolerance, 32u·|exact| + 32η, is 9.54e−7 here, computed in Python; no theorem covers this input and format. This lane is off by 3.05e−8, inside it.

TorchLean
logitsx₀9x₁−9x₂−9

logits

nodebitscomputedexacterror
x₀ = logit 00x488099exact
x₁ = logit 10xc880−9−9exact
x₂ = logit 20xc880−9−9exact
x − x[pivot]y₀0y₁−18y₂−18

x − x[pivot]

nodebitscomputedexacterror
y₀ = x0 − max0x000000exact
y₁ = x1 − max0xcc80−18−18exact
y₂ = x2 − max0xcc80−18−18exact
exp, off the pivote₁0e₂0

exp, off the pivot

nodebitscomputedexacterror
e₁ = exp(y1)0x000001.522998e−80 where the exact value is not
e₂ = exp(y2)0x000001.522998e−80 where the exact value is not
tail sumt₁0t₂0

tail sum

nodebitscomputedexacterror
t₁ = 0 + 0 + e10x000001.522998e−80 where the exact value is not
t₂ = t1 + e20x000003.0459959e−80 where the exact value is not
log1p of the taillog1p t0

log1p of the tail

nodebitscomputedexacterror
log1p t = log1p(t2)0x000003.0459959e−80 where the exact value is not
log-prob, losslog p₀0loss−0

log-prob, loss

nodebitscomputedexacterror
log p₀ = y0 − log s0x00000−3.0459959e−80 where the exact value is not
loss = −log p00x800003.0459959e−80 where the exact value is not
target gradientexpm10g₀0

target gradient

nodebitscomputedexacterror
expm1 = expm1(log p0)0x00000−3.0459959e−80 where the exact value is not
g₀ = −expm1(log p0)·(−1) − p0·00x00000−3.0459959e−80 where the exact value is not

The theorems' tolerance, 32u·|exact| + 32η, is 9.54e−7 here, computed in Python; no theorem covers this input and format. This lane is off by 3.05e−8, inside it.

The two small exponentials add up to 3.05e−8, less than half a unit of binary16 at 1, so the standard sum rounds to exactly 1. The standard target gradient is 0; the exact one is −3.046e−8. TorchLean's is 0 as well: exp of the gap, 1.52e−8, is less than half the smallest positive binary16 number (5.96e−8), so each exponential rounds to 0 before the sum. The correctly rounded gradient in binary16 is −5.96e−8.

Standard formula
logitsx₀9x₁−9x₂−9

logits

nodebitscomputedexacterror
x₀ = logit 00x402200000000000099exact
x₁ = logit 10xc022000000000000−9−9exact
x₂ = logit 20xc022000000000000−9−9exact
x − maxy₀0y₁−18y₂−18

x − max

nodebitscomputedexacterror
y₀ = x0 − max0x000000000000000000exact
y₁ = x1 − max0xc032000000000000−18−18exact
y₂ = x2 − max0xc032000000000000−18−18exact
expe₀1e₁1.523e−8e₂1.523e−8

exp

nodebitscomputedexacterror
e₀ = exp(y0)0x3ff000000000000011exact
e₁ = exp(y1)0x3e505a628c699fa11.522998e−81.522998e−80.22 units in the last place
e₂ = exp(y2)0x3e505a628c699fa11.522998e−81.522998e−80.22 units in the last place
running sums₀1s₁1s₂1

running sum

nodebitscomputedexacterror
s₀ = 0 + e00x3ff000000000000011exact
s₁ = s0 + e10x3ff00000041698a3110.1 units in the last place
s₂ = s1 + e20x3ff00000082d3146110.21 units in the last place
log of the sumlog s3.046e−8

log of the sum

nodebitscomputedexacterror
log s = log(s2)0x3e605a6287d24f163.0459959e−83.0459959e−86.9e6 units in the last place
log-prob, losslog p₀−3.046e−8loss3.046e−8

log-prob, loss

nodebitscomputedexacterror
log p₀ = y0 − log s0xbe605a6287d24f16−3.0459959e−8−3.0459959e−86.9e6 units in the last place
loss = −log p00x3e605a6287d24f163.0459959e−83.0459959e−86.9e6 units in the last place
target gradientp₀1g₀−3.046e−8

target gradient

nodebitscomputedexacterror
p₀ = e0 / s20x3fefffffefa59d7c0.999999970.999999970.056 units in the last place
g₀ = p0 − 10xbe605a6284000000−3.0459959e−8−3.0459959e−89.3e5 units in the last place

The theorems' tolerance, 32u·|exact| + 32η, is 1.08e−22 here, computed in Python; no theorem covers this input and format. This lane is off by 6.18e−18, outside it.

TorchLean
logitsx₀9x₁−9x₂−9

logits

nodebitscomputedexacterror
x₀ = logit 00x402200000000000099exact
x₁ = logit 10xc022000000000000−9−9exact
x₂ = logit 20xc022000000000000−9−9exact
x − x[pivot]y₀0y₁−18y₂−18

x − x[pivot]

nodebitscomputedexacterror
y₀ = x0 − max0x000000000000000000exact
y₁ = x1 − max0xc032000000000000−18−18exact
y₂ = x2 − max0xc032000000000000−18−18exact
exp, off the pivote₁1.523e−8e₂1.523e−8

exp, off the pivot

nodebitscomputedexacterror
e₁ = exp(y1)0x3e505a628c699fa11.522998e−81.522998e−80.22 units in the last place
e₂ = exp(y2)0x3e505a628c699fa11.522998e−81.522998e−80.22 units in the last place
tail sumt₁1.523e−8t₂3.046e−8

tail sum

nodebitscomputedexacterror
t₁ = 0 + 0 + e10x3e505a628c699fa11.522998e−81.522998e−80.22 units in the last place
t₂ = t1 + e20x3e605a628c699fa13.0459959e−83.0459959e−80.22 units in the last place
log1p of the taillog1p t3.046e−8

log1p of the tail

nodebitscomputedexacterror
log1p t = log1p(t2)0x3e605a62883beeb63.0459959e−83.0459959e−80.24 units in the last place
log-prob, losslog p₀−3.046e−8loss3.046e−8

log-prob, loss

nodebitscomputedexacterror
log p₀ = y0 − log s0xbe605a62883beeb6−3.0459959e−8−3.0459959e−80.24 units in the last place
loss = −log p00x3e605a62883beeb63.0459959e−83.0459959e−80.24 units in the last place
target gradientexpm1−3.046e−8g₀−3.046e−8

target gradient

nodebitscomputedexacterror
expm1 = expm1(log p0)0xbe605a62840e3dcd−3.0459959e−8−3.0459959e−80.12 units in the last place
g₀ = −expm1(log p0)·(−1) − p0·00xbe605a62840e3dcd−3.0459959e−8−3.0459959e−80.12 units in the last place

The theorems' tolerance, 32u·|exact| + 32η, is 1.08e−22 here, computed in Python; no theorem covers this input and format. This lane is off by 7.98e−25, inside it.

The standard target gradient is −3.046e−8, relative error 2e−10. TorchLean's is −3.046e−8, relative error 2.6e−17.

Standard formula
logitsx₀4x₁−4x₂−4

logits

nodebitscomputedexacterror
x₀ = logit 00x4080000044exact
x₁ = logit 10xc0800000−4−4exact
x₂ = logit 20xc0800000−4−4exact
x − maxy₀0y₁−8y₂−8

x − max

nodebitscomputedexacterror
y₀ = x0 − max0x0000000000exact
y₁ = x1 − max0xc1000000−8−8exact
y₂ = x2 − max0xc1000000−8−8exact
expe₀1e₁3.3546e−4e₂3.3546e−4

exp

nodebitscomputedexacterror
e₀ = exp(y0)0x3f80000011exact
e₁ = exp(y1)0x39afe1083.3546262e−43.3546263e−40.13 units in the last place
e₂ = exp(y2)0x39afe1083.3546262e−43.3546263e−40.13 units in the last place
running sums₀1s₁1.0003s₂1.0007

running sum

nodebitscomputedexacterror
s₀ = 0 + e00x3f80000011exact
s₁ = s0 + e10x3f800afe1.00033551.00033550.064 units in the last place
s₂ = s1 + e20x3f8015fc1.00067091.00067090.13 units in the last place
log of the sumlog s6.7068e−4

log of the sum

nodebitscomputedexacterror
log s = log(s2)0x3a2fd0e76.7068491e−46.7070029e−4260 units in the last place
log-prob, losslog p₀−6.7068e−4loss6.7068e−4

log-prob, loss

nodebitscomputedexacterror
log p₀ = y0 − log s0xba2fd0e7−6.7068491e−4−6.7070029e−4260 units in the last place
loss = −log p00x3a2fd0e76.7068491e−46.7070029e−4260 units in the last place
target gradientp₀0.99933g₀−6.7043e−4

target gradient

nodebitscomputedexacterror
p₀ = e0 / s20x3f7fd4100.999329570.999329520.71 units in the last place
g₀ = p0 − 10xba2fc000−6.7043304e−4−6.7047542e−4730 units in the last place

The theorems' tolerance, 32u·|exact| + 32η, is 1.28e−9 here, computed in Python; no theorem covers this input and format. This lane is off by 4.24e−8, outside it.

TorchLean
logitsx₀4x₁−4x₂−4

logits

nodebitscomputedexacterror
x₀ = logit 00x4080000044exact
x₁ = logit 10xc0800000−4−4exact
x₂ = logit 20xc0800000−4−4exact
x − x[pivot]y₀0y₁−8y₂−8

x − x[pivot]

nodebitscomputedexacterror
y₀ = x0 − max0x0000000000exact
y₁ = x1 − max0xc1000000−8−8exact
y₂ = x2 − max0xc1000000−8−8exact
exp, off the pivote₁3.3546e−4e₂3.3546e−4

exp, off the pivot

nodebitscomputedexacterror
e₁ = exp(y1)0x39afe1083.3546262e−43.3546263e−40.13 units in the last place
e₂ = exp(y2)0x39afe1083.3546262e−43.3546263e−40.13 units in the last place
tail sumt₁3.3546e−4t₂6.7093e−4

tail sum

nodebitscomputedexacterror
t₁ = 0 + 0 + e10x39afe1083.3546262e−43.3546263e−40.13 units in the last place
t₂ = t1 + e20x3a2fe1086.7092525e−46.7092526e−40.13 units in the last place
log1p of the taillog1p t6.707e−4

log1p of the tail

nodebitscomputedexacterror
log1p t = log1p(t2)0x3a2fd1ef6.7070028e−46.7070029e−40.18 units in the last place
log-prob, losslog p₀−6.707e−4loss6.707e−4

log-prob, loss

nodebitscomputedexacterror
log p₀ = y0 − log s0xba2fd1ef−6.7070028e−4−6.7070029e−40.18 units in the last place
loss = −log p00x3a2fd1ef6.7070028e−46.7070029e−40.18 units in the last place
target gradientexpm1−6.7048e−4g₀−6.7048e−4

target gradient

nodebitscomputedexacterror
expm1 = expm1(log p0)0xba2fc2d8−6.7047542e−4−6.7047542e−40.046 units in the last place
g₀ = −expm1(log p0)·(−1) − p0·00xba2fc2d8−6.7047542e−4−6.7047542e−40.046 units in the last place

The theorems' tolerance, 32u·|exact| + 32η, is 1.28e−9 here, computed in Python; no theorem covers this input and format. This lane is off by 2.7e−12, inside it.

The standard target gradient is −6.7043e−4, relative error 6.3e−5. TorchLean's is −6.7048e−4, relative error 4e−9.

Standard formula
logitsx₀4x₁−4x₂−4

logits

nodebitscomputedexacterror
x₀ = logit 00x408044exact
x₁ = logit 10xc080−4−4exact
x₂ = logit 20xc080−4−4exact
x − maxy₀0y₁−8y₂−8

x − max

nodebitscomputedexacterror
y₀ = x0 − max0x000000exact
y₁ = x1 − max0xc100−8−8exact
y₂ = x2 − max0xc100−8−8exact
expe₀1e₁3.3569e−4e₂3.3569e−4

exp

nodebitscomputedexacterror
e₀ = exp(y0)0x3f8011exact
e₁ = exp(y1)0x39b03.3569336e−43.3546263e−40.12 units in the last place
e₂ = exp(y2)0x39b03.3569336e−43.3546263e−40.12 units in the last place
running sums₀1s₁1s₂1rounds to 1

running sum

nodebitscomputedexacterror
s₀ = 0 + e00x3f8011exact
s₁ = s0 + e10x3f8011.00033550.043 units in the last place
s₂ = s1 + e20x3f8011.00067090.086 units in the last place
log of the sumlog s0

log of the sum

nodebitscomputedexacterror
log s = log(s2)0x000006.7070029e−40 where the exact value is not
log-prob, losslog p₀0loss−0

log-prob, loss

nodebitscomputedexacterror
log p₀ = y0 − log s0x00000−6.7070029e−40 where the exact value is not
loss = −log p00x800006.7070029e−40 where the exact value is not
target gradientp₀1g₀0

target gradient

nodebitscomputedexacterror
p₀ = e0 / s20x3f8010.999329520.17 units in the last place
g₀ = p0 − 10x00000−6.7047542e−40 where the exact value is not

Lean's theorems check this gradient: |computed − exact| ≤ 32u·|exact| + 32η = 8.38e−5. This lane is off by 6.7e−4, outside the bound.

TorchLean
logitsx₀4x₁−4x₂−4

logits

nodebitscomputedexacterror
x₀ = logit 00x408044exact
x₁ = logit 10xc080−4−4exact
x₂ = logit 20xc080−4−4exact
x − x[pivot]y₀0y₁−8y₂−8

x − x[pivot]

nodebitscomputedexacterror
y₀ = x0 − max0x000000exact
y₁ = x1 − max0xc100−8−8exact
y₂ = x2 − max0xc100−8−8exact
exp, off the pivote₁3.3569e−4e₂3.3569e−4

exp, off the pivot

nodebitscomputedexacterror
e₁ = exp(y1)0x39b03.3569336e−43.3546263e−40.12 units in the last place
e₂ = exp(y2)0x39b03.3569336e−43.3546263e−40.12 units in the last place
tail sumt₁3.3569e−4t₂6.7139e−4

tail sum

nodebitscomputedexacterror
t₁ = 0 + 0 + e10x39b03.3569336e−43.3546263e−40.12 units in the last place
t₂ = t1 + e20x3a306.7138672e−46.7092526e−40.12 units in the last place
log1p of the taillog1p t6.7139e−4

log1p of the tail

nodebitscomputedexacterror
log1p t = log1p(t2)0x3a306.7138672e−46.7070029e−40.18 units in the last place
log-prob, losslog p₀−6.7139e−4loss6.7139e−4

log-prob, loss

nodebitscomputedexacterror
log p₀ = y0 − log s0xba30−6.7138672e−4−6.7070029e−40.18 units in the last place
loss = −log p00x3a306.7138672e−46.7070029e−40.18 units in the last place
target gradientexpm1−6.7139e−4g₀−6.7139e−4

target gradient

nodebitscomputedexacterror
expm1 = expm1(log p0)0xba30−6.7138672e−4−6.7047542e−40.24 units in the last place
g₀ = −expm1(log p0)·(−1) − p0·00xba30−6.7138672e−4−6.7047542e−40.24 units in the last place

Lean's theorems check this gradient: |computed − exact| ≤ 32u·|exact| + 32η = 8.38e−5. This lane is off by 9.11e−7, inside the bound.

The two small exponentials add up to 6.71e−4, less than half a unit of bfloat16 at 1, so the standard sum rounds to exactly 1. The standard target gradient is 0; the exact one is −6.705e−4. TorchLean's is −6.7139e−4, relative error 0.0014.

Standard formula
logitsx₀4x₁−4x₂−4

logits

nodebitscomputedexacterror
x₀ = logit 00x440044exact
x₁ = logit 10xc400−4−4exact
x₂ = logit 20xc400−4−4exact
x − maxy₀0y₁−8y₂−8

x − max

nodebitscomputedexacterror
y₀ = x0 − max0x000000exact
y₁ = x1 − max0xc800−8−8exact
y₂ = x2 − max0xc800−8−8exact
expe₀1e₁3.3545e−4e₂3.3545e−4

exp

nodebitscomputedexacterror
e₀ = exp(y0)0x3c0011exact
e₁ = exp(y1)0x0d7f3.3545494e−43.3546263e−40.032 units in the last place
e₂ = exp(y2)0x0d7f3.3545494e−43.3546263e−40.032 units in the last place
running sums₀1s₁1s₂1rounds to 1

running sum

nodebitscomputedexacterror
s₀ = 0 + e00x3c0011exact
s₁ = s0 + e10x3c0011.00033550.34 units in the last place
s₂ = s1 + e20x3c0011.00067090.69 units in the last place
log of the sumlog s0

log of the sum

nodebitscomputedexacterror
log s = log(s2)0x000006.7070029e−40 where the exact value is not
log-prob, losslog p₀0loss−0

log-prob, loss

nodebitscomputedexacterror
log p₀ = y0 − log s0x00000−6.7070029e−40 where the exact value is not
loss = −log p00x800006.7070029e−40 where the exact value is not
target gradientp₀1g₀0

target gradient

nodebitscomputedexacterror
p₀ = e0 / s20x3c0010.999329521.4 units in the last place
g₀ = p0 − 10x00000−6.7047542e−40 where the exact value is not

The theorems' tolerance, 32u·|exact| + 32η, is 1.14e−5 here, computed in Python; no theorem covers this input and format. This lane is off by 6.7e−4, outside it.

TorchLean
logitsx₀4x₁−4x₂−4

logits

nodebitscomputedexacterror
x₀ = logit 00x440044exact
x₁ = logit 10xc400−4−4exact
x₂ = logit 20xc400−4−4exact
x − x[pivot]y₀0y₁−8y₂−8

x − x[pivot]

nodebitscomputedexacterror
y₀ = x0 − max0x000000exact
y₁ = x1 − max0xc800−8−8exact
y₂ = x2 − max0xc800−8−8exact
exp, off the pivote₁3.3545e−4e₂3.3545e−4

exp, off the pivot

nodebitscomputedexacterror
e₁ = exp(y1)0x0d7f3.3545494e−43.3546263e−40.032 units in the last place
e₂ = exp(y2)0x0d7f3.3545494e−43.3546263e−40.032 units in the last place
tail sumt₁3.3545e−4t₂6.7091e−4

tail sum

nodebitscomputedexacterror
t₁ = 0 + 0 + e10x0d7f3.3545494e−43.3546263e−40.032 units in the last place
t₂ = t1 + e20x117f6.7090988e−46.7092526e−40.032 units in the last place
log1p of the taillog1p t6.7091e−4

log1p of the tail

nodebitscomputedexacterror
log1p t = log1p(t2)0x117f6.7090988e−46.7070029e−40.44 units in the last place
log-prob, losslog p₀−6.7091e−4loss6.7091e−4

log-prob, loss

nodebitscomputedexacterror
log p₀ = y0 − log s0x917f−6.7090988e−4−6.7070029e−40.44 units in the last place
loss = −log p00x117f6.7090988e−46.7070029e−40.44 units in the last place
target gradientexpm1−6.7091e−4g₀−6.7091e−4

target gradient

nodebitscomputedexacterror
expm1 = expm1(log p0)0x917f−6.7090988e−4−6.7047542e−40.91 units in the last place
g₀ = −expm1(log p0)·(−1) − p0·00x917f−6.7090988e−4−6.7047542e−40.91 units in the last place

The theorems' tolerance, 32u·|exact| + 32η, is 1.14e−5 here, computed in Python; no theorem covers this input and format. This lane is off by 4.34e−7, inside it.

The two small exponentials add up to 6.71e−4, less than half a unit of binary16 at 1, so the standard sum rounds to exactly 1. The standard target gradient is 0; the exact one is −6.705e−4. TorchLean's is −6.7091e−4, relative error 6.5e−4.

Standard formula
logitsx₀4x₁−4x₂−4

logits

nodebitscomputedexacterror
x₀ = logit 00x401000000000000044exact
x₁ = logit 10xc010000000000000−4−4exact
x₂ = logit 20xc010000000000000−4−4exact
x − maxy₀0y₁−8y₂−8

x − max

nodebitscomputedexacterror
y₀ = x0 − max0x000000000000000000exact
y₁ = x1 − max0xc020000000000000−8−8exact
y₂ = x2 − max0xc020000000000000−8−8exact
expe₀1e₁3.3546e−4e₂3.3546e−4

exp

nodebitscomputedexacterror
e₀ = exp(y0)0x3ff000000000000011exact
e₁ = exp(y1)0x3f35fc21041027ad3.3546263e−43.3546263e−40.27 units in the last place
e₂ = exp(y2)0x3f35fc21041027ad3.3546263e−43.3546263e−40.27 units in the last place
running sums₀1s₁1.0003s₂1.0007

running sum

nodebitscomputedexacterror
s₀ = 0 + e00x3ff000000000000011exact
s₁ = s0 + e10x3ff0015fc21041021.00033551.00033550.48 units in the last place
s₂ = s1 + e20x3ff002bf842082041.00067091.00067090.96 units in the last place
log of the sumlog s6.707e−4

log of the sum

nodebitscomputedexacterror
log s = log(s2)0x3f45fa3de5a565256.7070029e−46.7070029e−42000 units in the last place
log-prob, losslog p₀−6.707e−4loss6.707e−4

log-prob, loss

nodebitscomputedexacterror
log p₀ = y0 − log s0xbf45fa3de5a56525−6.7070029e−4−6.7070029e−42000 units in the last place
loss = −log p00x3f45fa3de5a565256.7070029e−46.7070029e−42000 units in the last place
target gradientp₀0.99933g₀−6.7048e−4

target gradient

nodebitscomputedexacterror
p₀ = e0 / s20x3feffa81e9405ee00.999329520.999329521.7 units in the last place
g₀ = p0 − 10xbf45f85afe848000−6.7047542e−4−6.7047542e−41800 units in the last place

The theorems' tolerance, 32u·|exact| + 32η, is 2.38e−18 here, computed in Python; no theorem covers this input and format. This lane is off by 1.9e−16, outside it.

TorchLean
logitsx₀4x₁−4x₂−4

logits

nodebitscomputedexacterror
x₀ = logit 00x401000000000000044exact
x₁ = logit 10xc010000000000000−4−4exact
x₂ = logit 20xc010000000000000−4−4exact
x − x[pivot]y₀0y₁−8y₂−8

x − x[pivot]

nodebitscomputedexacterror
y₀ = x0 − max0x000000000000000000exact
y₁ = x1 − max0xc020000000000000−8−8exact
y₂ = x2 − max0xc020000000000000−8−8exact
exp, off the pivote₁3.3546e−4e₂3.3546e−4

exp, off the pivot

nodebitscomputedexacterror
e₁ = exp(y1)0x3f35fc21041027ad3.3546263e−43.3546263e−40.27 units in the last place
e₂ = exp(y2)0x3f35fc21041027ad3.3546263e−43.3546263e−40.27 units in the last place
tail sumt₁3.3546e−4t₂6.7093e−4

tail sum

nodebitscomputedexacterror
t₁ = 0 + 0 + e10x3f35fc21041027ad3.3546263e−43.3546263e−40.27 units in the last place
t₂ = t1 + e20x3f45fc21041027ad6.7092526e−46.7092526e−40.27 units in the last place
log1p of the taillog1p t6.707e−4

log1p of the tail

nodebitscomputedexacterror
log1p t = log1p(t2)0x3f45fa3de5a56cd06.7070029e−46.7070029e−40.2 units in the last place
log-prob, losslog p₀−6.707e−4loss6.707e−4

log-prob, loss

nodebitscomputedexacterror
log p₀ = y0 − log s0xbf45fa3de5a56cd0−6.7070029e−4−6.7070029e−40.2 units in the last place
loss = −log p00x3f45fa3de5a56cd06.7070029e−46.7070029e−40.2 units in the last place
target gradientexpm1−6.7048e−4g₀−6.7048e−4

target gradient

nodebitscomputedexacterror
expm1 = expm1(log p0)0xbf45f85afe8486db−6.7047542e−4−6.7047542e−40.38 units in the last place
g₀ = −expm1(log p0)·(−1) − p0·00xbf45f85afe8486db−6.7047542e−4−6.7047542e−40.38 units in the last place

The theorems' tolerance, 32u·|exact| + 32η, is 2.38e−18 here, computed in Python; no theorem covers this input and format. This lane is off by 4.14e−20, inside it.

The standard target gradient is −6.7048e−4, relative error 2.8e−13. TorchLean's is −6.7048e−4, relative error 6.2e−17.

Standard formula
logitsx₀19x₁−19x₂−19

logits

nodebitscomputedexacterror
x₀ = logit 00x419800001919exact
x₁ = logit 10xc1980000−19−19exact
x₂ = logit 20xc1980000−19−19exact
x − maxy₀0y₁−38y₂−38

x − max

nodebitscomputedexacterror
y₀ = x0 − max0x0000000000exact
y₁ = x1 − max0xc2180000−38−38exact
y₂ = x2 − max0xc2180000−38−38exact
expe₀1e₁3.1391e−17e₂3.1391e−17

exp

nodebitscomputedexacterror
e₀ = exp(y0)0x3f80000011exact
e₁ = exp(y1)0x2410c4573.1391329e−173.1391328e−170.29 units in the last place
e₂ = exp(y2)0x2410c4573.1391329e−173.1391328e−170.29 units in the last place
running sums₀1s₁1s₂1rounds to 1

running sum

nodebitscomputedexacterror
s₀ = 0 + e00x3f80000011exact
s₁ = s0 + e10x3f800000113.1e−17 relative
s₂ = s1 + e20x3f800000116.3e−17 relative
log of the sumlog s0

log of the sum

nodebitscomputedexacterror
log s = log(s2)0x0000000006.2782656e−170 where the exact value is not
log-prob, losslog p₀0loss−0

log-prob, loss

nodebitscomputedexacterror
log p₀ = y0 − log s0x000000000−6.2782656e−170 where the exact value is not
loss = −log p00x8000000006.2782656e−170 where the exact value is not
target gradientp₀1g₀0

target gradient

nodebitscomputedexacterror
p₀ = e0 / s20x3f800000116.3e−17 relative
g₀ = p0 − 10x000000000−6.2782656e−170 where the exact value is not

The theorems' tolerance, 32u·|exact| + 32η, is 1.2e−22 here, computed in Python; no theorem covers this input and format. This lane is off by 6.28e−17, outside it.

TorchLean
logitsx₀19x₁−19x₂−19

logits

nodebitscomputedexacterror
x₀ = logit 00x419800001919exact
x₁ = logit 10xc1980000−19−19exact
x₂ = logit 20xc1980000−19−19exact
x − x[pivot]y₀0y₁−38y₂−38

x − x[pivot]

nodebitscomputedexacterror
y₀ = x0 − max0x0000000000exact
y₁ = x1 − max0xc2180000−38−38exact
y₂ = x2 − max0xc2180000−38−38exact
exp, off the pivote₁3.1391e−17e₂3.1391e−17

exp, off the pivot

nodebitscomputedexacterror
e₁ = exp(y1)0x2410c4573.1391329e−173.1391328e−170.29 units in the last place
e₂ = exp(y2)0x2410c4573.1391329e−173.1391328e−170.29 units in the last place
tail sumt₁3.1391e−17t₂6.2783e−17

tail sum

nodebitscomputedexacterror
t₁ = 0 + 0 + e10x2410c4573.1391329e−173.1391328e−170.29 units in the last place
t₂ = t1 + e20x2490c4576.2782658e−176.2782656e−170.29 units in the last place
log1p of the taillog1p t6.2783e−17

log1p of the tail

nodebitscomputedexacterror
log1p t = log1p(t2)0x2490c4576.2782658e−176.2782656e−170.29 units in the last place
log-prob, losslog p₀−6.2783e−17loss6.2783e−17

log-prob, loss

nodebitscomputedexacterror
log p₀ = y0 − log s0xa490c457−6.2782658e−17−6.2782656e−170.29 units in the last place
loss = −log p00x2490c4576.2782658e−176.2782656e−170.29 units in the last place
target gradientexpm1−6.2783e−17g₀−6.2783e−17

target gradient

nodebitscomputedexacterror
expm1 = expm1(log p0)0xa490c457−6.2782658e−17−6.2782656e−170.29 units in the last place
g₀ = −expm1(log p0)·(−1) − p0·00xa490c457−6.2782658e−17−6.2782656e−170.29 units in the last place

The theorems' tolerance, 32u·|exact| + 32η, is 1.2e−22 here, computed in Python; no theorem covers this input and format. This lane is off by 1.93e−24, inside it.

The two small exponentials add up to 6.28e−17, less than half a unit of binary32 at 1, so the standard sum rounds to exactly 1. The standard target gradient is 0; the exact one is −6.278e−17. TorchLean's is −6.2783e−17, relative error 3.1e−8.

Standard formula
logitsx₀19x₁−19x₂−19

logits

nodebitscomputedexacterror
x₀ = logit 00x41981919exact
x₁ = logit 10xc198−19−19exact
x₂ = logit 20xc198−19−19exact
x − maxy₀0y₁−38y₂−38

x − max

nodebitscomputedexacterror
y₀ = x0 − max0x000000exact
y₁ = x1 − max0xc218−38−38exact
y₂ = x2 − max0xc218−38−38exact
expe₀1e₁3.1442e−17e₂3.1442e−17

exp

nodebitscomputedexacterror
e₀ = exp(y0)0x3f8011exact
e₁ = exp(y1)0x24113.1441863e−173.1391328e−170.23 units in the last place
e₂ = exp(y2)0x24113.1441863e−173.1391328e−170.23 units in the last place
running sums₀1s₁1s₂1rounds to 1

running sum

nodebitscomputedexacterror
s₀ = 0 + e00x3f8011exact
s₁ = s0 + e10x3f80113.1e−17 relative
s₂ = s1 + e20x3f80116.3e−17 relative
log of the sumlog s0

log of the sum

nodebitscomputedexacterror
log s = log(s2)0x000006.2782656e−170 where the exact value is not
log-prob, losslog p₀0loss−0

log-prob, loss

nodebitscomputedexacterror
log p₀ = y0 − log s0x00000−6.2782656e−170 where the exact value is not
loss = −log p00x800006.2782656e−170 where the exact value is not
target gradientp₀1g₀0

target gradient

nodebitscomputedexacterror
p₀ = e0 / s20x3f80116.3e−17 relative
g₀ = p0 − 10x00000−6.2782656e−170 where the exact value is not

The theorems' tolerance, 32u·|exact| + 32η, is 7.85e−18 here, computed in Python; no theorem covers this input and format. This lane is off by 6.28e−17, outside it.

TorchLean
logitsx₀19x₁−19x₂−19

logits

nodebitscomputedexacterror
x₀ = logit 00x41981919exact
x₁ = logit 10xc198−19−19exact
x₂ = logit 20xc198−19−19exact
x − x[pivot]y₀0y₁−38y₂−38

x − x[pivot]

nodebitscomputedexacterror
y₀ = x0 − max0x000000exact
y₁ = x1 − max0xc218−38−38exact
y₂ = x2 − max0xc218−38−38exact
exp, off the pivote₁3.1442e−17e₂3.1442e−17

exp, off the pivot

nodebitscomputedexacterror
e₁ = exp(y1)0x24113.1441863e−173.1391328e−170.23 units in the last place
e₂ = exp(y2)0x24113.1441863e−173.1391328e−170.23 units in the last place
tail sumt₁3.1442e−17t₂6.2884e−17

tail sum

nodebitscomputedexacterror
t₁ = 0 + 0 + e10x24113.1441863e−173.1391328e−170.23 units in the last place
t₂ = t1 + e20x24916.2883726e−176.2782656e−170.23 units in the last place
log1p of the taillog1p t6.2884e−17

log1p of the tail

nodebitscomputedexacterror
log1p t = log1p(t2)0x24916.2883726e−176.2782656e−170.23 units in the last place
log-prob, losslog p₀−6.2884e−17loss6.2884e−17

log-prob, loss

nodebitscomputedexacterror
log p₀ = y0 − log s0xa491−6.2883726e−17−6.2782656e−170.23 units in the last place
loss = −log p00x24916.2883726e−176.2782656e−170.23 units in the last place
target gradientexpm1−6.2884e−17g₀−6.2884e−17

target gradient

nodebitscomputedexacterror
expm1 = expm1(log p0)0xa491−6.2883726e−17−6.2782656e−170.23 units in the last place
g₀ = −expm1(log p0)·(−1) − p0·00xa491−6.2883726e−17−6.2782656e−170.23 units in the last place

The theorems' tolerance, 32u·|exact| + 32η, is 7.85e−18 here, computed in Python; no theorem covers this input and format. This lane is off by 1.01e−19, inside it.

The two small exponentials add up to 6.28e−17, less than half a unit of bfloat16 at 1, so the standard sum rounds to exactly 1. The standard target gradient is 0; the exact one is −6.278e−17. TorchLean's is −6.2884e−17, relative error 0.0016.

Standard formula
logitsx₀19x₁−19x₂−19

logits

nodebitscomputedexacterror
x₀ = logit 00x4cc01919exact
x₁ = logit 10xccc0−19−19exact
x₂ = logit 20xccc0−19−19exact
x − maxy₀0y₁−38y₂−38

x − max

nodebitscomputedexacterror
y₀ = x0 − max0x000000exact
y₁ = x1 − max0xd0c0−38−38exact
y₂ = x2 − max0xd0c0−38−38exact
expe₀1e₁0e₂0

exp

nodebitscomputedexacterror
e₀ = exp(y0)0x3c0011exact
e₁ = exp(y1)0x000003.1391328e−170 where the exact value is not
e₂ = exp(y2)0x000003.1391328e−170 where the exact value is not
running sums₀1s₁1s₂1rounds to 1

running sum

nodebitscomputedexacterror
s₀ = 0 + e00x3c0011exact
s₁ = s0 + e10x3c00113.1e−17 relative
s₂ = s1 + e20x3c00116.3e−17 relative
log of the sumlog s0

log of the sum

nodebitscomputedexacterror
log s = log(s2)0x000006.2782656e−170 where the exact value is not
log-prob, losslog p₀0loss−0

log-prob, loss

nodebitscomputedexacterror
log p₀ = y0 − log s0x00000−6.2782656e−170 where the exact value is not
loss = −log p00x800006.2782656e−170 where the exact value is not
target gradientp₀1g₀0

target gradient

nodebitscomputedexacterror
p₀ = e0 / s20x3c00116.3e−17 relative
g₀ = p0 − 10x00000−6.2782656e−170 where the exact value is not

The theorems' tolerance, 32u·|exact| + 32η, is 9.54e−7 here, computed in Python; no theorem covers this input and format. This lane is off by 6.28e−17, inside it.

TorchLean
logitsx₀19x₁−19x₂−19

logits

nodebitscomputedexacterror
x₀ = logit 00x4cc01919exact
x₁ = logit 10xccc0−19−19exact
x₂ = logit 20xccc0−19−19exact
x − x[pivot]y₀0y₁−38y₂−38

x − x[pivot]

nodebitscomputedexacterror
y₀ = x0 − max0x000000exact
y₁ = x1 − max0xd0c0−38−38exact
y₂ = x2 − max0xd0c0−38−38exact
exp, off the pivote₁0e₂0

exp, off the pivot

nodebitscomputedexacterror
e₁ = exp(y1)0x000003.1391328e−170 where the exact value is not
e₂ = exp(y2)0x000003.1391328e−170 where the exact value is not
tail sumt₁0t₂0

tail sum

nodebitscomputedexacterror
t₁ = 0 + 0 + e10x000003.1391328e−170 where the exact value is not
t₂ = t1 + e20x000006.2782656e−170 where the exact value is not
log1p of the taillog1p t0

log1p of the tail

nodebitscomputedexacterror
log1p t = log1p(t2)0x000006.2782656e−170 where the exact value is not
log-prob, losslog p₀0loss−0

log-prob, loss

nodebitscomputedexacterror
log p₀ = y0 − log s0x00000−6.2782656e−170 where the exact value is not
loss = −log p00x800006.2782656e−170 where the exact value is not
target gradientexpm10g₀0

target gradient

nodebitscomputedexacterror
expm1 = expm1(log p0)0x00000−6.2782656e−170 where the exact value is not
g₀ = −expm1(log p0)·(−1) − p0·00x00000−6.2782656e−170 where the exact value is not

The theorems' tolerance, 32u·|exact| + 32η, is 9.54e−7 here, computed in Python; no theorem covers this input and format. This lane is off by 6.28e−17, inside it.

The two small exponentials add up to 6.28e−17, less than half a unit of binary16 at 1, so the standard sum rounds to exactly 1. The standard target gradient is 0; the exact one is −6.278e−17. TorchLean's is 0 as well: exp of the gap, 3.14e−17, is less than half the smallest positive binary16 number (5.96e−8), so each exponential rounds to 0 before the sum. Here 0 is also the correctly rounded gradient.

Standard formula
logitsx₀19x₁−19x₂−19

logits

nodebitscomputedexacterror
x₀ = logit 00x40330000000000001919exact
x₁ = logit 10xc033000000000000−19−19exact
x₂ = logit 20xc033000000000000−19−19exact
x − maxy₀0y₁−38y₂−38

x − max

nodebitscomputedexacterror
y₀ = x0 − max0x000000000000000000exact
y₁ = x1 − max0xc043000000000000−38−38exact
y₂ = x2 − max0xc043000000000000−38−38exact
expe₀1e₁3.1391e−17e₂3.1391e−17

exp

nodebitscomputedexacterror
e₀ = exp(y0)0x3ff000000000000011exact
e₁ = exp(y1)0x3c82188ad6ae33033.1391328e−173.1391328e−170.054 units in the last place
e₂ = exp(y2)0x3c82188ad6ae33033.1391328e−173.1391328e−170.054 units in the last place
running sums₀1s₁1s₂1rounds to 1

running sum

nodebitscomputedexacterror
s₀ = 0 + e00x3ff000000000000011exact
s₁ = s0 + e10x3ff0000000000000110.14 units in the last place
s₂ = s1 + e20x3ff0000000000000110.28 units in the last place
log of the sumlog s0

log of the sum

nodebitscomputedexacterror
log s = log(s2)0x000000000000000006.2782656e−170 where the exact value is not
log-prob, losslog p₀0loss−0

log-prob, loss

nodebitscomputedexacterror
log p₀ = y0 − log s0x00000000000000000−6.2782656e−170 where the exact value is not
loss = −log p00x800000000000000006.2782656e−170 where the exact value is not
target gradientp₀1g₀0

target gradient

nodebitscomputedexacterror
p₀ = e0 / s20x3ff0000000000000110.57 units in the last place
g₀ = p0 − 10x00000000000000000−6.2782656e−170 where the exact value is not

Lean's theorems check this gradient: |computed − exact| ≤ 32u·|exact| + 32η = 2.23e−31. This lane is off by 6.28e−17, outside the bound.

TorchLean
logitsx₀19x₁−19x₂−19

logits

nodebitscomputedexacterror
x₀ = logit 00x40330000000000001919exact
x₁ = logit 10xc033000000000000−19−19exact
x₂ = logit 20xc033000000000000−19−19exact
x − x[pivot]y₀0y₁−38y₂−38

x − x[pivot]

nodebitscomputedexacterror
y₀ = x0 − max0x000000000000000000exact
y₁ = x1 − max0xc043000000000000−38−38exact
y₂ = x2 − max0xc043000000000000−38−38exact
exp, off the pivote₁3.1391e−17e₂3.1391e−17

exp, off the pivot

nodebitscomputedexacterror
e₁ = exp(y1)0x3c82188ad6ae33033.1391328e−173.1391328e−170.054 units in the last place
e₂ = exp(y2)0x3c82188ad6ae33033.1391328e−173.1391328e−170.054 units in the last place
tail sumt₁3.1391e−17t₂6.2783e−17

tail sum

nodebitscomputedexacterror
t₁ = 0 + 0 + e10x3c82188ad6ae33033.1391328e−173.1391328e−170.054 units in the last place
t₂ = t1 + e20x3c92188ad6ae33036.2782656e−176.2782656e−170.054 units in the last place
log1p of the taillog1p t6.2783e−17

log1p of the tail

nodebitscomputedexacterror
log1p t = log1p(t2)0x3c92188ad6ae33036.2782656e−176.2782656e−170.11 units in the last place
log-prob, losslog p₀−6.2783e−17loss6.2783e−17

log-prob, loss

nodebitscomputedexacterror
log p₀ = y0 − log s0xbc92188ad6ae3303−6.2782656e−17−6.2782656e−170.11 units in the last place
loss = −log p00x3c92188ad6ae33036.2782656e−176.2782656e−170.11 units in the last place
target gradientexpm1−6.2783e−17g₀−6.2783e−17

target gradient

nodebitscomputedexacterror
expm1 = expm1(log p0)0xbc92188ad6ae3303−6.2782656e−17−6.2782656e−170.27 units in the last place
g₀ = −expm1(log p0)·(−1) − p0·00xbc92188ad6ae3303−6.2782656e−17−6.2782656e−170.27 units in the last place

Lean's theorems check this gradient: |computed − exact| ≤ 32u·|exact| + 32η = 2.23e−31. This lane is off by 3.28e−33, inside the bound.

The two small exponentials add up to 6.28e−17, less than half a unit of binary64 at 1, so the standard sum rounds to exactly 1. The standard target gradient is 0; the exact one is −6.278e−17. TorchLean's is −6.2783e−17, relative error 5.2e−17.

Standard formula
logitsx₀20x₁10x₂0

logits

nodebitscomputedexacterror
x₀ = logit 00x41a000002020exact
x₁ = logit 10x412000001010exact
x₂ = logit 20x0000000000exact
x − maxy₀0y₁−10y₂−20

x − max

nodebitscomputedexacterror
y₀ = x0 − max0x0000000000exact
y₁ = x1 − max0xc1200000−10−10exact
y₂ = x2 − max0xc1a00000−20−20exact
expe₀1e₁4.54e−5e₂2.0612e−9

exp

nodebitscomputedexacterror
e₀ = exp(y0)0x3f80000011exact
e₁ = exp(y1)0x383e6bce4.5399931e−54.539993e−50.33 units in the last place
e₂ = exp(y2)0x310da4332.0611537e−92.0611536e−90.31 units in the last place
running sums₀1s₁1s₂1

running sum

nodebitscomputedexacterror
s₀ = 0 + e00x3f80000011exact
s₁ = s0 + e10x3f80017d1.00004541.00004540.16 units in the last place
s₂ = s1 + e20x3f80017d1.00004541.00004540.14 units in the last place
log of the sumlog s4.5418e−5

log of the sum

nodebitscomputedexacterror
log s = log(s2)0x383e7ee44.5417706e−54.540096e−54600 units in the last place
log-prob, losslog p₀−4.5418e−5loss4.5418e−5

log-prob, loss

nodebitscomputedexacterror
log p₀ = y0 − log s0xb83e7ee4−4.5417706e−5−4.540096e−54600 units in the last place
loss = −log p00x383e7ee44.5417706e−54.540096e−54600 units in the last place
target gradientp₀0.99995g₀−4.5419e−5

target gradient

nodebitscomputedexacterror
p₀ = e0 / s20x3f7ffd060.999954580.99995460.32 units in the last place
g₀ = p0 − 10xb83e8000−4.5418739e−5−4.539993e−55200 units in the last place

The theorems' tolerance, 32u·|exact| + 32η, is 8.66e−11 here, computed in Python; no theorem covers this input and format. This lane is off by 1.88e−8, outside it.

TorchLean
logitsx₀20x₁10x₂0

logits

nodebitscomputedexacterror
x₀ = logit 00x41a000002020exact
x₁ = logit 10x412000001010exact
x₂ = logit 20x0000000000exact
x − x[pivot]y₀0y₁−10y₂−20

x − x[pivot]

nodebitscomputedexacterror
y₀ = x0 − max0x0000000000exact
y₁ = x1 − max0xc1200000−10−10exact
y₂ = x2 − max0xc1a00000−20−20exact
exp, off the pivote₁4.54e−5e₂2.0612e−9

exp, off the pivot

nodebitscomputedexacterror
e₁ = exp(y1)0x383e6bce4.5399931e−54.539993e−50.33 units in the last place
e₂ = exp(y2)0x310da4332.0611537e−92.0611536e−90.31 units in the last place
tail sumt₁4.54e−5t₂4.5402e−5

tail sum

nodebitscomputedexacterror
t₁ = 0 + 0 + e10x383e6bce4.5399931e−54.539993e−50.33 units in the last place
t₂ = t1 + e20x383e6e054.5401994e−54.5401991e−50.77 units in the last place
log1p of the taillog1p t4.5401e−5

log1p of the tail

nodebitscomputedexacterror
log1p t = log1p(t2)0x383e6cea4.5400964e−54.540096e−51.1 units in the last place
log-prob, losslog p₀−4.5401e−5loss4.5401e−5

log-prob, loss

nodebitscomputedexacterror
log p₀ = y0 − log s0xb83e6cea−4.5400964e−5−4.540096e−51.1 units in the last place
loss = −log p00x383e6cea4.5400964e−54.540096e−51.1 units in the last place
target gradientexpm1−4.54e−5g₀−4.54e−5

target gradient

nodebitscomputedexacterror
expm1 = expm1(log p0)0xb83e6bcf−4.5399935e−5−4.539993e−51.4 units in the last place
g₀ = −expm1(log p0)·(−1) − p0·00xb83e6bcf−4.5399935e−5−4.539993e−51.4 units in the last place

The theorems' tolerance, 32u·|exact| + 32η, is 8.66e−11 here, computed in Python; no theorem covers this input and format. This lane is off by 4.94e−12, inside it.

The standard target gradient is −4.5419e−5, relative error 4.1e−4. TorchLean's is −4.54e−5, relative error 1.1e−7.

Standard formula
logitsx₀20x₁10x₂0

logits

nodebitscomputedexacterror
x₀ = logit 00x41a02020exact
x₁ = logit 10x41201010exact
x₂ = logit 20x000000exact
x − maxy₀0y₁−10y₂−20

x − max

nodebitscomputedexacterror
y₀ = x0 − max0x000000exact
y₁ = x1 − max0xc120−10−10exact
y₂ = x2 − max0xc1a0−20−20exact
expe₀1e₁4.53e−5e₂2.0664e−9

exp

nodebitscomputedexacterror
e₀ = exp(y0)0x3f8011exact
e₁ = exp(y1)0x383e4.529953e−54.539993e−50.42 units in the last place
e₂ = exp(y2)0x310e2.066372e−92.0611536e−90.36 units in the last place
running sums₀1s₁1s₂1rounds to 1

running sum

nodebitscomputedexacterror
s₀ = 0 + e00x3f8011exact
s₁ = s0 + e10x3f8011.00004544.5e−5 relative
s₂ = s1 + e20x3f8011.00004544.5e−5 relative
log of the sumlog s0

log of the sum

nodebitscomputedexacterror
log s = log(s2)0x000004.540096e−50 where the exact value is not
log-prob, losslog p₀0loss−0

log-prob, loss

nodebitscomputedexacterror
log p₀ = y0 − log s0x00000−4.540096e−50 where the exact value is not
loss = −log p00x800004.540096e−50 where the exact value is not
target gradientp₀1g₀0

target gradient

nodebitscomputedexacterror
p₀ = e0 / s20x3f8010.99995460.012 units in the last place
g₀ = p0 − 10x00000−4.539993e−50 where the exact value is not

The theorems' tolerance, 32u·|exact| + 32η, is 5.67e−6 here, computed in Python; no theorem covers this input and format. This lane is off by 4.54e−5, outside it.

TorchLean
logitsx₀20x₁10x₂0

logits

nodebitscomputedexacterror
x₀ = logit 00x41a02020exact
x₁ = logit 10x41201010exact
x₂ = logit 20x000000exact
x − x[pivot]y₀0y₁−10y₂−20

x − x[pivot]

nodebitscomputedexacterror
y₀ = x0 − max0x000000exact
y₁ = x1 − max0xc120−10−10exact
y₂ = x2 − max0xc1a0−20−20exact
exp, off the pivote₁4.53e−5e₂2.0664e−9

exp, off the pivot

nodebitscomputedexacterror
e₁ = exp(y1)0x383e4.529953e−54.539993e−50.42 units in the last place
e₂ = exp(y2)0x310e2.066372e−92.0611536e−90.36 units in the last place
tail sumt₁4.53e−5t₂4.53e−5

tail sum

nodebitscomputedexacterror
t₁ = 0 + 0 + e10x383e4.529953e−54.539993e−50.42 units in the last place
t₂ = t1 + e20x383e4.529953e−54.5401991e−50.43 units in the last place
log1p of the taillog1p t4.53e−5

log1p of the tail

nodebitscomputedexacterror
log1p t = log1p(t2)0x383e4.529953e−54.540096e−50.43 units in the last place
log-prob, losslog p₀−4.53e−5loss4.53e−5

log-prob, loss

nodebitscomputedexacterror
log p₀ = y0 − log s0xb83e−4.529953e−5−4.540096e−50.43 units in the last place
loss = −log p00x383e4.529953e−54.540096e−50.43 units in the last place
target gradientexpm1−4.53e−5g₀−4.53e−5

target gradient

nodebitscomputedexacterror
expm1 = expm1(log p0)0xb83e−4.529953e−5−4.539993e−50.42 units in the last place
g₀ = −expm1(log p0)·(−1) − p0·00xb83e−4.529953e−5−4.539993e−50.42 units in the last place

The theorems' tolerance, 32u·|exact| + 32η, is 5.67e−6 here, computed in Python; no theorem covers this input and format. This lane is off by 1e−7, inside it.

The two small exponentials add up to 4.54e−5, less than half a unit of bfloat16 at 1, so the standard sum rounds to exactly 1. The standard target gradient is 0; the exact one is −4.54e−5. TorchLean's is −4.53e−5, relative error 0.0022.

Standard formula
logitsx₀20x₁10x₂0

logits

nodebitscomputedexacterror
x₀ = logit 00x4d002020exact
x₁ = logit 10x49001010exact
x₂ = logit 20x000000exact
x − maxy₀0y₁−10y₂−20

x − max

nodebitscomputedexacterror
y₀ = x0 − max0x000000exact
y₁ = x1 − max0xc900−10−10exact
y₂ = x2 − max0xcd00−20−20exact
expe₀1e₁4.5419e−5e₂0

exp

nodebitscomputedexacterror
e₀ = exp(y0)0x3c0011exact
e₁ = exp(y1)0x02fa4.5418739e−54.539993e−50.32 units in the last place
e₂ = exp(y2)0x000002.0611536e−90 where the exact value is not
running sums₀1s₁1s₂1rounds to 1

running sum

nodebitscomputedexacterror
s₀ = 0 + e00x3c0011exact
s₁ = s0 + e10x3c0011.00004540.046 units in the last place
s₂ = s1 + e20x3c0011.00004540.046 units in the last place
log of the sumlog s0

log of the sum

nodebitscomputedexacterror
log s = log(s2)0x000004.540096e−50 where the exact value is not
log-prob, losslog p₀0loss−0

log-prob, loss

nodebitscomputedexacterror
log p₀ = y0 − log s0x00000−4.540096e−50 where the exact value is not
loss = −log p00x800004.540096e−50 where the exact value is not
target gradientp₀1g₀0

target gradient

nodebitscomputedexacterror
p₀ = e0 / s20x3c0010.99995460.093 units in the last place
g₀ = p0 − 10x00000−4.539993e−50 where the exact value is not

The theorems' tolerance, 32u·|exact| + 32η, is 1.66e−6 here, computed in Python; no theorem covers this input and format. This lane is off by 4.54e−5, outside it.

TorchLean
logitsx₀20x₁10x₂0

logits

nodebitscomputedexacterror
x₀ = logit 00x4d002020exact
x₁ = logit 10x49001010exact
x₂ = logit 20x000000exact
x − x[pivot]y₀0y₁−10y₂−20

x − x[pivot]

nodebitscomputedexacterror
y₀ = x0 − max0x000000exact
y₁ = x1 − max0xc900−10−10exact
y₂ = x2 − max0xcd00−20−20exact
exp, off the pivote₁4.5419e−5e₂0

exp, off the pivot

nodebitscomputedexacterror
e₁ = exp(y1)0x02fa4.5418739e−54.539993e−50.32 units in the last place
e₂ = exp(y2)0x000002.0611536e−90 where the exact value is not
tail sumt₁4.5419e−5t₂4.5419e−5

tail sum

nodebitscomputedexacterror
t₁ = 0 + 0 + e10x02fa4.5418739e−54.539993e−50.32 units in the last place
t₂ = t1 + e20x02fa4.5418739e−54.5401991e−50.28 units in the last place
log1p of the taillog1p t4.5419e−5

log1p of the tail

nodebitscomputedexacterror
log1p t = log1p(t2)0x02fa4.5418739e−54.540096e−50.3 units in the last place
log-prob, losslog p₀−4.5419e−5loss4.5419e−5

log-prob, loss

nodebitscomputedexacterror
log p₀ = y0 − log s0x82fa−4.5418739e−5−4.540096e−50.3 units in the last place
loss = −log p00x02fa4.5418739e−54.540096e−50.3 units in the last place
target gradientexpm1−4.5419e−5g₀−4.5419e−5

target gradient

nodebitscomputedexacterror
expm1 = expm1(log p0)0x82fa−4.5418739e−5−4.539993e−50.32 units in the last place
g₀ = −expm1(log p0)·(−1) − p0·00x82fa−4.5418739e−5−4.539993e−50.32 units in the last place

The theorems' tolerance, 32u·|exact| + 32η, is 1.66e−6 here, computed in Python; no theorem covers this input and format. This lane is off by 1.88e−8, inside it.

The two small exponentials add up to 4.54e−5, less than half a unit of binary16 at 1, so the standard sum rounds to exactly 1. The standard target gradient is 0; the exact one is −4.54e−5. TorchLean's is −4.5419e−5, relative error 4.1e−4.

Standard formula
logitsx₀20x₁10x₂0

logits

nodebitscomputedexacterror
x₀ = logit 00x40340000000000002020exact
x₁ = logit 10x40240000000000001010exact
x₂ = logit 20x000000000000000000exact
x − maxy₀0y₁−10y₂−20

x − max

nodebitscomputedexacterror
y₀ = x0 − max0x000000000000000000exact
y₁ = x1 − max0xc024000000000000−10−10exact
y₂ = x2 − max0xc034000000000000−20−20exact
expe₀1e₁4.54e−5e₂2.0612e−9

exp

nodebitscomputedexacterror
e₀ = exp(y0)0x3ff000000000000011exact
e₁ = exp(y1)0x3f07cd79b5647c9b4.539993e−54.539993e−50.39 units in the last place
e₂ = exp(y2)0x3e21b48655f372672.0611536e−92.0611536e−90.1 units in the last place
running sums₀1s₁1s₂1

running sum

nodebitscomputedexacterror
s₀ = 0 + e00x3ff000000000000011exact
s₁ = s0 + e10x3ff0002f9af36ac91.00004541.00004540.027 units in the last place
s₂ = s1 + e20x3ff0002f9b810efc1.00004541.00004540.34 units in the last place
log of the sumlog s4.5401e−5

log of the sum

nodebitscomputedexacterror
log s = log(s2)0x3f07cd9d1de4dab14.540096e−54.540096e−511000 units in the last place
log-prob, losslog p₀−4.5401e−5loss4.5401e−5

log-prob, loss

nodebitscomputedexacterror
log p₀ = y0 − log s0xbf07cd9d1de4dab1−4.540096e−5−4.540096e−511000 units in the last place
loss = −log p00x3f07cd9d1de4dab14.540096e−54.540096e−511000 units in the last place
target gradientp₀0.99995g₀−4.54e−5

target gradient

nodebitscomputedexacterror
p₀ = e0 / s20x3fefffa0ca192db80.99995460.99995460.87 units in the last place
g₀ = p0 − 10xbf07cd79b4920000−4.539993e−5−4.539993e−514000 units in the last place

The theorems' tolerance, 32u·|exact| + 32η, is 1.61e−19 here, computed in Python; no theorem covers this input and format. This lane is off by 9.71e−17, outside it.

TorchLean
logitsx₀20x₁10x₂0

logits

nodebitscomputedexacterror
x₀ = logit 00x40340000000000002020exact
x₁ = logit 10x40240000000000001010exact
x₂ = logit 20x000000000000000000exact
x − x[pivot]y₀0y₁−10y₂−20

x − x[pivot]

nodebitscomputedexacterror
y₀ = x0 − max0x000000000000000000exact
y₁ = x1 − max0xc024000000000000−10−10exact
y₂ = x2 − max0xc034000000000000−20−20exact
exp, off the pivote₁4.54e−5e₂2.0612e−9

exp, off the pivot

nodebitscomputedexacterror
e₁ = exp(y1)0x3f07cd79b5647c9b4.539993e−54.539993e−50.39 units in the last place
e₂ = exp(y2)0x3e21b48655f372672.0611536e−92.0611536e−90.1 units in the last place
tail sumt₁4.54e−5t₂4.5402e−5

tail sum

nodebitscomputedexacterror
t₁ = 0 + 0 + e10x3f07cd79b5647c9b4.539993e−54.539993e−50.39 units in the last place
t₂ = t1 + e20x3f07cdc0877dd4694.5401991e−54.5401991e−50.6 units in the last place
log1p of the taillog1p t4.5401e−5

log1p of the tail

nodebitscomputedexacterror
log1p t = log1p(t2)0x3f07cd9d1de4af1b4.540096e−54.540096e−50.81 units in the last place
log-prob, losslog p₀−4.5401e−5loss4.5401e−5

log-prob, loss

nodebitscomputedexacterror
log p₀ = y0 − log s0xbf07cd9d1de4af1b−4.540096e−5−4.540096e−50.81 units in the last place
loss = −log p00x3f07cd9d1de4af1b4.540096e−54.540096e−50.81 units in the last place
target gradientexpm1−4.54e−5g₀−4.54e−5

target gradient

nodebitscomputedexacterror
expm1 = expm1(log p0)0xbf07cd79b491c808−4.539993e−5−4.539993e−50.53 units in the last place
g₀ = −expm1(log p0)·(−1) − p0·00xbf07cd79b491c808−4.539993e−5−4.539993e−50.53 units in the last place

The theorems' tolerance, 32u·|exact| + 32η, is 1.61e−19 here, computed in Python; no theorem covers this input and format. This lane is off by 3.57e−21, inside it.

The standard target gradient is −4.54e−5, relative error 2.1e−12. TorchLean's is −4.54e−5, relative error 7.9e−17.

Standard formula
logitsx₀2x₁1x₂0

logits

nodebitscomputedexacterror
x₀ = logit 00x4000000022exact
x₁ = logit 10x3f80000011exact
x₂ = logit 20x0000000000exact
x − maxy₀0y₁−1y₂−2

x − max

nodebitscomputedexacterror
y₀ = x0 − max0x0000000000exact
y₁ = x1 − max0xbf800000−1−1exact
y₂ = x2 − max0xc0000000−2−2exact
expe₀1e₁0.36788e₂0.13534

exp

nodebitscomputedexacterror
e₀ = exp(y0)0x3f80000011exact
e₁ = exp(y1)0x3ebc5ab20.367879450.367879440.31 units in the last place
e₂ = exp(y2)0x3e0a95550.135335280.135335280.12 units in the last place
running sums₀1s₁1.3679s₂1.5032

running sum

nodebitscomputedexacterror
s₀ = 0 + e00x3f80000011exact
s₁ = s0 + e10x3faf16ac1.36787941.36787940.42 units in the last place
s₂ = s1 + e20x3fc069571.50321471.50321470.063 units in the last place
log of the sumlog s0.40761

log of the sum

nodebitscomputedexacterror
log s = log(s2)0x3ed0b1ba0.407605950.407605960.62 units in the last place
log-prob, losslog p₀−0.40761loss0.40761

log-prob, loss

nodebitscomputedexacterror
log p₀ = y0 − log s0xbed0b1ba−0.40760595−0.407605960.62 units in the last place
loss = −log p00x3ed0b1ba0.407605950.407605960.62 units in the last place
target gradientp₀0.66524g₀−0.33476

target gradient

nodebitscomputedexacterror
p₀ = e0 / s20x3f2a4d3b0.665240940.665240960.21 units in the last place
g₀ = p0 − 10xbeab658a−0.33475906−0.334759040.41 units in the last place

The theorems' tolerance, 32u·|exact| + 32η, is 6.39e−7 here, computed in Python; no theorem covers this input and format. This lane is off by 1.23e−8, inside it.

TorchLean
logitsx₀2x₁1x₂0

logits

nodebitscomputedexacterror
x₀ = logit 00x4000000022exact
x₁ = logit 10x3f80000011exact
x₂ = logit 20x0000000000exact
x − x[pivot]y₀0y₁−1y₂−2

x − x[pivot]

nodebitscomputedexacterror
y₀ = x0 − max0x0000000000exact
y₁ = x1 − max0xbf800000−1−1exact
y₂ = x2 − max0xc0000000−2−2exact
exp, off the pivote₁0.36788e₂0.13534

exp, off the pivot

nodebitscomputedexacterror
e₁ = exp(y1)0x3ebc5ab20.367879450.367879440.31 units in the last place
e₂ = exp(y2)0x3e0a95550.135335280.135335280.12 units in the last place
tail sumt₁0.36788t₂0.50321

tail sum

nodebitscomputedexacterror
t₁ = 0 + 0 + e10x3ebc5ab20.367879450.367879440.31 units in the last place
t₂ = t1 + e20x3f00d2ae0.503214720.503214720.13 units in the last place
log1p of the taillog1p t0.40761

log1p of the tail

nodebitscomputedexacterror
log1p t = log1p(t2)0x3ed0b1ba0.407605950.407605960.62 units in the last place
log-prob, losslog p₀−0.40761loss0.40761

log-prob, loss

nodebitscomputedexacterror
log p₀ = y0 − log s0xbed0b1ba−0.40760595−0.407605960.62 units in the last place
loss = −log p00x3ed0b1ba0.407605950.407605960.62 units in the last place
target gradientexpm1−0.33476g₀−0.33476

target gradient

nodebitscomputedexacterror
expm1 = expm1(log p0)0xbeab6589−0.33475903−0.334759040.59 units in the last place
g₀ = −expm1(log p0)·(−1) − p0·00xbeab6589−0.33475903−0.334759040.59 units in the last place

The theorems' tolerance, 32u·|exact| + 32η, is 6.39e−7 here, computed in Python; no theorem covers this input and format. This lane is off by 1.75e−8, inside it.

The standard target gradient is −0.33476, relative error 3.7e−8. TorchLean's is −0.33476, relative error 5.2e−8.

Standard formula
logitsx₀2x₁1x₂0

logits

nodebitscomputedexacterror
x₀ = logit 00x400022exact
x₁ = logit 10x3f8011exact
x₂ = logit 20x000000exact
x − maxy₀0y₁−1y₂−2

x − max

nodebitscomputedexacterror
y₀ = x0 − max0x000000exact
y₁ = x1 − max0xbf80−1−1exact
y₂ = x2 − max0xc000−2−2exact
expe₀1e₁0.36719e₂0.13574

exp

nodebitscomputedexacterror
e₀ = exp(y0)0x3f8011exact
e₁ = exp(y1)0x3ebc0.36718750.367879440.35 units in the last place
e₂ = exp(y2)0x3e0b0.135742190.135335280.42 units in the last place
running sums₀1s₁1.3672s₂1.5

running sum

nodebitscomputedexacterror
s₀ = 0 + e00x3f8011exact
s₁ = s0 + e10x3faf1.36718751.36787940.089 units in the last place
s₂ = s1 + e20x3fc01.51.50321470.41 units in the last place
log of the sumlog s0.40625

log of the sum

nodebitscomputedexacterror
log s = log(s2)0x3ed00.406250.407605960.69 units in the last place
log-prob, losslog p₀−0.40625loss0.40625

log-prob, loss

nodebitscomputedexacterror
log p₀ = y0 − log s0xbed0−0.40625−0.407605960.69 units in the last place
loss = −log p00x3ed00.406250.407605960.69 units in the last place
target gradientp₀0.66797g₀−0.33203

target gradient

nodebitscomputedexacterror
p₀ = e0 / s20x3f2b0.667968750.665240960.7 units in the last place
g₀ = p0 − 10xbeaa−0.33203125−0.334759041.4 units in the last place

The theorems' tolerance, 32u·|exact| + 32η, is 0.0418 here, computed in Python; no theorem covers this input and format. This lane is off by 0.00273, inside it.

TorchLean
logitsx₀2x₁1x₂0

logits

nodebitscomputedexacterror
x₀ = logit 00x400022exact
x₁ = logit 10x3f8011exact
x₂ = logit 20x000000exact
x − x[pivot]y₀0y₁−1y₂−2

x − x[pivot]

nodebitscomputedexacterror
y₀ = x0 − max0x000000exact
y₁ = x1 − max0xbf80−1−1exact
y₂ = x2 − max0xc000−2−2exact
exp, off the pivote₁0.36719e₂0.13574

exp, off the pivot

nodebitscomputedexacterror
e₁ = exp(y1)0x3ebc0.36718750.367879440.35 units in the last place
e₂ = exp(y2)0x3e0b0.135742190.135335280.42 units in the last place
tail sumt₁0.36719t₂0.50391

tail sum

nodebitscomputedexacterror
t₁ = 0 + 0 + e10x3ebc0.36718750.367879440.35 units in the last place
t₂ = t1 + e20x3f010.503906250.503214720.18 units in the last place
log1p of the taillog1p t0.4082

log1p of the tail

nodebitscomputedexacterror
log1p t = log1p(t2)0x3ed10.408203130.407605960.31 units in the last place
log-prob, losslog p₀−0.4082loss0.4082

log-prob, loss

nodebitscomputedexacterror
log p₀ = y0 − log s0xbed1−0.40820313−0.407605960.31 units in the last place
loss = −log p00x3ed10.408203130.407605960.31 units in the last place
target gradientexpm1−0.33594g₀−0.33594

target gradient

nodebitscomputedexacterror
expm1 = expm1(log p0)0xbeac−0.3359375−0.334759040.6 units in the last place
g₀ = −expm1(log p0)·(−1) − p0·00xbeac−0.3359375−0.334759040.6 units in the last place

The theorems' tolerance, 32u·|exact| + 32η, is 0.0418 here, computed in Python; no theorem covers this input and format. This lane is off by 0.00118, inside it.

The standard target gradient is −0.33203, relative error 0.0081. TorchLean's is −0.33594, relative error 0.0035.

Standard formula
logitsx₀2x₁1x₂0

logits

nodebitscomputedexacterror
x₀ = logit 00x400022exact
x₁ = logit 10x3c0011exact
x₂ = logit 20x000000exact
x − maxy₀0y₁−1y₂−2

x − max

nodebitscomputedexacterror
y₀ = x0 − max0x000000exact
y₁ = x1 − max0xbc00−1−1exact
y₂ = x2 − max0xc000−2−2exact
expe₀1e₁0.36792e₂0.13538

exp

nodebitscomputedexacterror
e₀ = exp(y0)0x3c0011exact
e₁ = exp(y1)0x35e30.367919920.367879440.17 units in the last place
e₂ = exp(y2)0x30550.135375980.135335280.33 units in the last place
running sums₀1s₁1.3682s₂1.5039

running sum

nodebitscomputedexacterror
s₀ = 0 + e00x3c0011exact
s₁ = s0 + e10x3d791.36816411.36787940.29 units in the last place
s₂ = s1 + e20x3e041.50390631.50321470.71 units in the last place
log of the sumlog s0.40796

log of the sum

nodebitscomputedexacterror
log s = log(s2)0x36870.407958980.407605961.4 units in the last place
log-prob, losslog p₀−0.40796loss0.40796

log-prob, loss

nodebitscomputedexacterror
log p₀ = y0 − log s0xb687−0.40795898−0.407605961.4 units in the last place
loss = −log p00x36870.407958980.407605961.4 units in the last place
target gradientp₀0.66504g₀−0.33496

target gradient

nodebitscomputedexacterror
p₀ = e0 / s20x39520.665039060.665240960.41 units in the last place
g₀ = p0 − 10xb55c−0.33496094−0.334759040.83 units in the last place

The theorems' tolerance, 32u·|exact| + 32η, is 0.00523 here, computed in Python; no theorem covers this input and format. This lane is off by 2.02e−4, inside it.

TorchLean
logitsx₀2x₁1x₂0

logits

nodebitscomputedexacterror
x₀ = logit 00x400022exact
x₁ = logit 10x3c0011exact
x₂ = logit 20x000000exact
x − x[pivot]y₀0y₁−1y₂−2

x − x[pivot]

nodebitscomputedexacterror
y₀ = x0 − max0x000000exact
y₁ = x1 − max0xbc00−1−1exact
y₂ = x2 − max0xc000−2−2exact
exp, off the pivote₁0.36792e₂0.13538

exp, off the pivot

nodebitscomputedexacterror
e₁ = exp(y1)0x35e30.367919920.367879440.17 units in the last place
e₂ = exp(y2)0x30550.135375980.135335280.33 units in the last place
tail sumt₁0.36792t₂0.50342

tail sum

nodebitscomputedexacterror
t₁ = 0 + 0 + e10x35e30.367919920.367879440.17 units in the last place
t₂ = t1 + e20x38070.503417970.503214720.42 units in the last place
log1p of the taillog1p t0.40771

log1p of the tail

nodebitscomputedexacterror
log1p t = log1p(t2)0x36860.407714840.407605960.45 units in the last place
log-prob, losslog p₀−0.40771loss0.40771

log-prob, loss

nodebitscomputedexacterror
log p₀ = y0 − log s0xb686−0.40771484−0.407605960.45 units in the last place
loss = −log p00x36860.407714840.407605960.45 units in the last place
target gradientexpm1−0.33472g₀−0.33472

target gradient

nodebitscomputedexacterror
expm1 = expm1(log p0)0xb55b−0.3347168−0.334759040.17 units in the last place
g₀ = −expm1(log p0)·(−1) − p0·00xb55b−0.3347168−0.334759040.17 units in the last place

The theorems' tolerance, 32u·|exact| + 32η, is 0.00523 here, computed in Python; no theorem covers this input and format. This lane is off by 4.22e−5, inside it.

The standard target gradient is −0.33496, relative error 6e−4. TorchLean's is −0.33472, relative error 1.3e−4.

Standard formula
logitsx₀2x₁1x₂0

logits

nodebitscomputedexacterror
x₀ = logit 00x400000000000000022exact
x₁ = logit 10x3ff000000000000011exact
x₂ = logit 20x000000000000000000exact
x − maxy₀0y₁−1y₂−2

x − max

nodebitscomputedexacterror
y₀ = x0 − max0x000000000000000000exact
y₁ = x1 − max0xbff0000000000000−1−1exact
y₂ = x2 − max0xc000000000000000−2−2exact
expe₀1e₁0.36788e₂0.13534

exp

nodebitscomputedexacterror
e₀ = exp(y0)0x3ff000000000000011exact
e₁ = exp(y1)0x3fd78b56362cef380.367879440.367879440.22 units in the last place
e₂ = exp(y2)0x3fc152aaa3bf81cc0.135335280.135335280.38 units in the last place
running sums₀1s₁1.3679s₂1.5032

running sum

nodebitscomputedexacterror
s₀ = 0 + e00x3ff000000000000011exact
s₁ = s0 + e10x3ff5e2d58d8b3bce1.36787941.36787940.056 units in the last place
s₂ = s1 + e20x3ff80d2ae2032c081.50321471.50321470.6 units in the last place
log of the sumlog s0.40761

log of the sum

nodebitscomputedexacterror
log s = log(s2)0x3fda163753bc5c9d0.407605960.407605961.9 units in the last place
log-prob, losslog p₀−0.40761loss0.40761

log-prob, loss

nodebitscomputedexacterror
log p₀ = y0 − log s0xbfda163753bc5c9d−0.40760596−0.407605961.9 units in the last place
loss = −log p00x3fda163753bc5c9d0.407605960.407605961.9 units in the last place
target gradientp₀0.66524g₀−0.33476

target gradient

nodebitscomputedexacterror
p₀ = e0 / s20x3fe549a766a067900.665240960.665240960.94 units in the last place
g₀ = p0 − 10xbfd56cb132bf30e0−0.33475904−0.334759041.9 units in the last place

The theorems' tolerance, 32u·|exact| + 32η, is 1.19e−15 here, computed in Python; no theorem covers this input and format. This lane is off by 1.05e−16, inside it.

TorchLean
logitsx₀2x₁1x₂0

logits

nodebitscomputedexacterror
x₀ = logit 00x400000000000000022exact
x₁ = logit 10x3ff000000000000011exact
x₂ = logit 20x000000000000000000exact
x − x[pivot]y₀0y₁−1y₂−2

x − x[pivot]

nodebitscomputedexacterror
y₀ = x0 − max0x000000000000000000exact
y₁ = x1 − max0xbff0000000000000−1−1exact
y₂ = x2 − max0xc000000000000000−2−2exact
exp, off the pivote₁0.36788e₂0.13534

exp, off the pivot

nodebitscomputedexacterror
e₁ = exp(y1)0x3fd78b56362cef380.367879440.367879440.22 units in the last place
e₂ = exp(y2)0x3fc152aaa3bf81cc0.135335280.135335280.38 units in the last place
tail sumt₁0.36788t₂0.50321

tail sum

nodebitscomputedexacterror
t₁ = 0 + 0 + e10x3fd78b56362cef380.367879440.367879440.22 units in the last place
t₂ = t1 + e20x3fe01a55c406580f0.503214720.503214720.21 units in the last place
log1p of the taillog1p t0.40761

log1p of the tail

nodebitscomputedexacterror
log1p t = log1p(t2)0x3fda163753bc5c9b0.407605960.407605960.12 units in the last place
log-prob, losslog p₀−0.40761loss0.40761

log-prob, loss

nodebitscomputedexacterror
log p₀ = y0 − log s0xbfda163753bc5c9b−0.40760596−0.407605960.12 units in the last place
loss = −log p00x3fda163753bc5c9b0.407605960.407605960.12 units in the last place
target gradientexpm1−0.33476g₀−0.33476

target gradient

nodebitscomputedexacterror
expm1 = expm1(log p0)0xbfd56cb132bf30de−0.33475904−0.334759040.12 units in the last place
g₀ = −expm1(log p0)·(−1) − p0·00xbfd56cb132bf30de−0.33475904−0.334759040.12 units in the last place

The theorems' tolerance, 32u·|exact| + 32η, is 1.19e−15 here, computed in Python; no theorem covers this input and format. This lane is off by 6.48e−18, inside it.

The standard target gradient is −0.33476, relative error 3.1e−16. TorchLean's is −0.33476, relative error 1.9e−17.

Figure 2. Where the softmax calculation loses the gradient.The standard and replacement formulas use the same input and number format. In the default float32 example, adding the small exponentials to 1 erases their contribution. Keeping their sum separate preserves it. Black highlights a computed zero whose real-valued reference is nonzero.
Arithmetic and reference values

Values were evaluated in Lean with FloatLib. References use mpmath at 256 bits. The per-step records include computed values, reference values, errors, and bit patterns.

Other failures in losses and updates

We then modeled fifteen more formulas in Lean and checked the corresponding calls in the libraries. Most CPU results reproduced the predicted failures; the exception was PyTorch's fused bfloat16 tanh GELU, which computes in float32. GPU behavior sometimes differed, so the figure below keeps the devices separate. One example is the KL estimator used in TRL's GRPO training code. If \(d\) is the difference between two log probabilities, the estimator is:

\[ \begin{aligned} k(d)&=e^d-d-1,\\ e^d&\approx1+d+\tfrac12d^2\quad\text{near zero}. \end{aligned} \]

Near zero, those subtractions are supposed to leave a small positive penalty. At \(d=2^{-12}\) in float32, the direct expression returned zero instead of roughly \(3.0\times10^{-8}\); expm1(d) - d kept the value. We also saw PyTorch's KL divergence between nearby normal distributions return zero in one test and a negative value in another. Diffusion noise schedules expose a similar problem. Their noise level uses \(\sqrt{1-\alpha}\), where \(\alpha\) is a product of schedule values. In our binary16 example, \(\alpha\) rounded to 1, so the computed noise level vanished instead of being about 0.0148. Accumulating the logarithms and using expm1 to recover the small difference avoided that failure.

Some failures come from intermediate overflow rather than cancellation. A binary16 label smoothed cross entropy overflowed its batch sum and returned infinity instead of 1875. Log sum exp over 151,936 zeros should be about 11.93, but summing that many ones overflowed in several tested implementations; accumulating in float32 fixes it. Soft margin loss at \(-12\) in binary16 returned an infinite loss and a NaN gradient. Small constants can be just as dangerous. In one float32 clamp, eps=1e-8 disappeared from the upper limit \(1-\mathrm{eps}\), which rounded to 1 and produced infinity later. TorchLean's safeDiv adds \(10^{-6}\) to the denominator, but safeDiv(1, 0) still overflows in binary16 and E5M2. Stable Baselines3's squashed Gaussian uses an epsilon that changes the mathematical function itself; we count that separately rather than calling it a rounding failure.

A finite loss does not necessarily mean the gradient is usable either. An ℓ₃ norm on binary16 entries of \(2^{-13}\) produced a NaN gradient instead of about 0.397, while focal loss with exponent \(1/2\) produced zero loss and a NaN gradient at a float32 logit of \(-20\). We also found updates that simply stopped changing the state: a bfloat16 moving average stayed at \(1/64\) for 5,000 steps because every update rounded away, and an xLSTM memory decay rounded to 1 instead of about 0.9526.

Matches modelDifferent resultMixed across calls or formatsNot tested

Case and library callsInput and format Original formula (Lean)CPU resultA100 result Replacement (Lean)
Softmax Collapse
Softmax cross-entropy, PyTorchF.log_softmax, F.cross_entropy and its backward[9, −9, −9] float32; [4, −4, −4] bfloat16; [19, −19, −19] float640 (log-probability, loss and target gradient)Matches modelin all three formatsMixed resultsfloat32 and float64 same; bfloat16 gives −11/214, the correctly rounded value−2143429/246 in float32, −11/214 in bfloat16
Softmax cross-entropy, JAXjax.nn.log_softmax, optax's softmax_cross_entropy_with_integer_labels, jax.grad[9, −9, −9] float32; [4, −4, −4] bfloat16; [19, −19, −19] float640Matches modelin all three formatsMatches modelin all three formats−2143429/246 in float32, −11/214 in bfloat16
One plus something small
tanh-GELU, float32F.gelu(approximate='tanh'), gelu_new, gelu_pytorch_tanh, jax.nn.gelux = −6, float32−0Matches modelall fourMatches modelall four−3040709/255
tanh-GELU, bfloat16F.gelu(approximate='tanh'), gelu_new, gelu_pytorch_tanh, jax.nn.gelux = −4, bfloat16−0Mixed resultsgelu_new and jax.nn.gelu same; F.gelu and gelu_pytorch_tanh give −147/221Mixed resultsgelu_new same; F.gelu and gelu_pytorch_tanh give −147/221, jax.nn.gelu −75/220−149/221
GRPO's k3 KL penaltyTRL's GRPO line in PyTorch; the same expression under jax.jitd = 2−12, float32; d = 2−6, bfloat160Matches modelMatches model2−25 in float32
KL divergence of two normalskl_divergence of two Normals; of two 1-d MultivariateNormalsN(0, 1) and N(2−13, 1); σ = 1 and 1 + 2−13, float320; −2−27Matches modelMatches model2−27; 2047/237
Clamped logittorch.special.logit(x, eps=1e-8), torch.logitx = 1, float32+∞Matches modelMatches model4828871/218
DDPM noise leveldiffusers' DDPMScheduler.add_noiset = 1, binary160Matches modelMatches model243/214
Focal loss, γ = ½torchvision's sigmoid_focal_loss and its backwardlogit −20, target 0, float32loss 0, gradient NaNMatches modelMatches modelgradient 10357061/266
Weibull survival functionTFP's Weibull(5, 1).survival_function, log_survival_functionx = 2, float320 and −∞Matches modelNot testedCPU build only1868901/267 and −32
Moving average of weightsget_ema_multi_avg_fn(0.999)average 1/64, parameter 69/212, bfloat161/64 after every stepMatches modelfor 5,000 stepsMatches modelfor 5,000 stepsfloat32 average: 8389263/229 after one step
xLSTM forget gatexlstm's mLSTM, parallel_stabilized_simplerunning sum −64, log gate −199/212, bfloat16decay 1Matches modelMatches model61/64
Overflow before the division
Label smoothingF.cross_entropy(label_smoothing=0.125)3 rows [0, −30000], binary16+∞Matches modelMatches model1875
Log-sum-exptorch.logsumexp, F.log_softmax, F.cross_entropy; jax.nn.logsumexp, jax.nn.log_softmax, optax151,936 zeros, binary16±∞Matches modelPyTorch and JAXMixed resultstorch.logsumexp and JAX same; PyTorch's log_softmax and cross_entropy give ±1527/27±1527/27, with the sum in float32
Soft-margin lossF.soft_margin_loss and its backwardx = −12, binary16; x = −100, float32loss +∞, gradient NaNMatches modelMatches model12 and −1 in binary16
Backward of a 3-normtorch.linalg.vector_norm(ord=3)four entries 2−13, binary16NaNMatches modelMatches model407/1024
Cancellation
VariancePyTorch Geometric's VarAggregation, StdAggregation[4095, 4097, 4097], float32variance −2, standard deviation 0Matches modelMatches model14913081/224
A documented epsilon
Squashed GaussianStable-Baselines3's TanhBijector.log_prob_correctionu = 10, float32−14486613/220Matches modelMatches model−4879471/218
Figure 3. Formula models and library results.The model columns evaluate the original formula and its replacement in Lean. CPU and A100 results show whether the actual library call matched the original formula's modeled result. Matching can include the same zero, infinity, or NaN; a fused kernel or wider internal arithmetic can change the outcome.
Arithmetic and reference values

The two Lean columns use the first format listed for each case. A matching library result is either bit-for-bit identical or reproduces the same zero, infinity, or NaN. The CPU runs used an x86-64 machine running PyTorch's AVX-512 kernels.

For the direct KL formula, the generated absolute error allowance is larger than the penalty we're trying to measure. That bound still allows zero, so it doesn't tell us whether the small penalty survives rounding.

Precision and range are different problems

There are two separate limits in a floating point format. The fraction bits determine the spacing between nearby values, while the exponent bits determine the range. More fraction bits cannot save an answer that underflows, and a wider exponent range will not fix cancellation near 1. This is why bfloat16, with roughly the range of float32 but much coarser spacing, behaves differently from float16, which has more fraction bits near 1 but a much narrower range.

FormatExponent bitsFraction bitsGap above 1Largest finite valueSmallest normal value
float641152\(2.2\times10^{-16}\)\(1.8\times10^{308}\)\(2.2\times10^{-308}\)
float32823\(1.2\times10^{-7}\)\(3.4\times10^{38}\)\(1.2\times10^{-38}\)
TF32810\(9.8\times10^{-4}\)\(3.4\times10^{38}\)\(1.2\times10^{-38}\)
bfloat1687\(7.8\times10^{-3}\)\(3.4\times10^{38}\)\(1.2\times10^{-38}\)
float16510\(9.8\times10^{-4}\)65,504\(6.1\times10^{-5}\)
E5M2520.2557,344\(6.1\times10^{-5}\)
E4M3FN430.1254480.0156

With FloatLib, we compared four original formulas and their replacements across 526 formats: 520 choices of exponent and fraction widths, three more float8 layouts, and three posit formats. The sweep below uses the same inputs for the original and rewritten expressions, so you can see whether a zero comes from precision, range, or the particular formula.

Figure 4. Every format, before and after the rewrite.Each square is one number format, with more exponent bits going down the side and more fraction bits going right. The squares fill in with the formula as libraries write it, then again with the rewrite. Black is a wrong zero, red is infinity or NaN, blue is the relative error against the exact value, and a green outline marks a format the rewrite fixed. What stays wrong is range: formats too short to hold the numbers. Values: Lean with FloatLib, with exact references from mpmath at 256 bits.

The softmax example makes the distinction especially clear. When the exponent range is sufficient, the original target gradient stays zero through 24 fraction bits. At 25 fraction bits it becomes nonzero, but is still nearly twice the true value. The rewrite avoids that precision problem. In very narrow formats, however, even the rewritten expression can return zero when the exponentials themselves underflow. Binary16 is one such case. That is why we also added the underflow fallback described below.

Exponent bits
Fraction bits
exact−3.045995856×10−8

e = 4, f = 1

standard0no correct digits
TorchLean0no correct digits

With 1 fraction bit the logit 9 is stored as 8, so both formulas compute the gradient for [8, −8, −8], not the exact value above. e−18 = 1.52e−8 is less than half a unit at 1, 2−2 = 0.25, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

e−18 is less than half the smallest positive number, 0.00781, so it rounds to 0 before anything is added.

e = 4, f = 2

standard0no correct digits
TorchLean0no correct digits

With 2 fraction bits the logit 9 is stored as 8, so both formulas compute the gradient for [8, −8, −8], not the exact value above. e−18 = 1.52e−8 is less than half a unit at 1, 2−3 = 0.125, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

e−18 is less than half the smallest positive number, 0.00391, so it rounds to 0 before anything is added.

e = 4, f = 3

standard0no correct digits
TorchLean0no correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−4 = 0.0625, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

e−18 is less than half the smallest positive number, 0.00195, so it rounds to 0 before anything is added.

e = 4, f = 4

standard0no correct digits
TorchLean0no correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−5 = 0.0313, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

e−18 is less than half the smallest positive number, 9.77e−4, so it rounds to 0 before anything is added.

e = 4, f = 5

standard0no correct digits
TorchLean0no correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−6 = 0.0156, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

e−18 is less than half the smallest positive number, 4.88e−4, so it rounds to 0 before anything is added.

e = 4, f = 6

standard0no correct digits
TorchLean0no correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−7 = 0.00781, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

e−18 is less than half the smallest positive number, 2.44e−4, so it rounds to 0 before anything is added.

e = 4, f = 7

standard0no correct digits
TorchLean0no correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−8 = 0.00391, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

e−18 is less than half the smallest positive number, 1.22e−4, so it rounds to 0 before anything is added.

e = 4, f = 8

standard0no correct digits
TorchLean0no correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−9 = 0.00195, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

e−18 is less than half the smallest positive number, 6.1e−5, so it rounds to 0 before anything is added.

e = 4, f = 9

standard0no correct digits
TorchLean0no correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−10 = 9.77e−4, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

e−18 is less than half the smallest positive number, 3.05e−5, so it rounds to 0 before anything is added.

e = 4, f = 10

standard0no correct digits
TorchLean0no correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−11 = 4.88e−4, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

e−18 is less than half the smallest positive number, 1.53e−5, so it rounds to 0 before anything is added.

e = 4, f = 11

standard0no correct digits
TorchLean0no correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−12 = 2.44e−4, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

e−18 is less than half the smallest positive number, 7.63e−6, so it rounds to 0 before anything is added.

e = 4, f = 12

standard0no correct digits
TorchLean0no correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−13 = 1.22e−4, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

e−18 is less than half the smallest positive number, 3.81e−6, so it rounds to 0 before anything is added.

e = 4, f = 13

standard0no correct digits
TorchLean0no correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−14 = 6.1e−5, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

e−18 is less than half the smallest positive number, 1.91e−6, so it rounds to 0 before anything is added.

e = 4, f = 14

standard0no correct digits
TorchLean0no correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−15 = 3.05e−5, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

e−18 is less than half the smallest positive number, 9.54e−7, so it rounds to 0 before anything is added.

e = 4, f = 15

standard0no correct digits
TorchLean0no correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−16 = 1.53e−5, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

e−18 is less than half the smallest positive number, 4.77e−7, so it rounds to 0 before anything is added.

e = 4, f = 16

standard0no correct digits
TorchLean0no correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−17 = 7.63e−6, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

e−18 is less than half the smallest positive number, 2.38e−7, so it rounds to 0 before anything is added.

e = 4, f = 17

standard0no correct digits
TorchLean0no correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−18 = 3.81e−6, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

e−18 is less than half the smallest positive number, 1.19e−7, so it rounds to 0 before anything is added.

e = 4, f = 18

standard0no correct digits
TorchLean0no correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−19 = 1.91e−6, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

e−18 is less than half the smallest positive number, 5.96e−8, so it rounds to 0 before anything is added.

e = 4, f = 19

standard0no correct digits
TorchLean−5.960464478×10−8no correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−20 = 9.54e−7, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

e−18 is between half the smallest positive number and the smallest positive number, 2.98e−8, so it rounds up to 2.98e−8, about twice its value.

e = 4, f = 20

standard0no correct digits
TorchLean−2.980232239×10−8no correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−21 = 4.77e−7, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

e−18 is below the smallest normal number, 0.0156, so it keeps only 1 significant bit.

e = 4, f = 21

standard0no correct digits
TorchLean−2.980232239×10−8no correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−22 = 2.38e−7, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

e−18 is below the smallest normal number, 0.0156, so it keeps only 2 significant bits.

e = 4, f = 22

standard0no correct digits
TorchLean−2.980232239×10−8no correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−23 = 1.19e−7, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

e−18 is below the smallest normal number, 0.0156, so it keeps only 3 significant bits.

e = 4, f = 23

standard0no correct digits
TorchLean−2.980232239×10−8no correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−24 = 5.96e−8, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

e−18 is below the smallest normal number, 0.0156, so it keeps only 4 significant bits.

e = 4, f = 24

standard0no correct digits
TorchLean−2.980232239×10−8no correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−25 = 2.98e−8, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

e−18 is below the smallest normal number, 0.0156, so it keeps only 5 significant bits.

e = 4, f = 25

standard−5.960464478×10−8no correct digits
TorchLean−3.073364496×10−82 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−26 = 1.49e−8, so the sum moves off 1. But p0 is rounded to a multiple of that same 1.49e−8, and so is p0 − 1, against a gradient of 3.05e−8.

e−18 is below the smallest normal number, 0.0156, so it keeps only 6 significant bits.

e = 4, f = 26

standard−2.980232239×10−8no correct digits
TorchLean−3.026798368×10−82 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−27 = 7.45e−9, so the sum moves off 1. But p0 is rounded to a multiple of that same 7.45e−9, and so is p0 − 1, against a gradient of 3.05e−8.

e−18 is below the smallest normal number, 0.0156, so it keeps only 7 significant bits.

e = 4, f = 27

standard−2.980232239×10−8no correct digits
TorchLean−3.050081432×10−82 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−28 = 3.73e−9, so the sum moves off 1. But p0 is rounded to a multiple of that same 3.73e−9, and so is p0 − 1, against a gradient of 3.05e−8.

e−18 is below the smallest normal number, 0.0156, so it keeps only 8 significant bits.

e = 4, f = 28

standard−2.980232239×10−8no correct digits
TorchLean−3.050081432×10−82 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−29 = 1.86e−9, so the sum moves off 1. But p0 is rounded to a multiple of that same 1.86e−9, and so is p0 − 1, against a gradient of 3.05e−8.

e−18 is below the smallest normal number, 0.0156, so it keeps only 9 significant bits.

e = 4, f = 29

standard−2.980232239×10−8no correct digits
TorchLean−3.044260666×10−83 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−30 = 9.31e−10, so the sum moves off 1. But p0 is rounded to a multiple of that same 9.31e−10, and so is p0 − 1, against a gradient of 3.05e−8.

e−18 is below the smallest normal number, 0.0156, so it keeps only 10 significant bits.

e = 4, f = 30

standard−2.980232239×10−8no correct digits
TorchLean−3.047171049×10−83 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−31 = 4.66e−10, so the sum moves off 1. But p0 is rounded to a multiple of that same 4.66e−10, and so is p0 − 1, against a gradient of 3.05e−8.

e−18 is below the smallest normal number, 0.0156, so it keeps only 11 significant bits.

e = 4, f = 31

standard−3.073364496×10−82 correct digits
TorchLean−3.045715857×10−84 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−32 = 2.33e−10, so the sum moves off 1. But p0 is rounded to a multiple of that same 2.33e−10, and so is p0 − 1, against a gradient of 3.05e−8.

e−18 is below the smallest normal number, 0.0156, so it keeps only 12 significant bits.

e = 4, f = 32

standard−3.026798368×10−82 correct digits
TorchLean−3.045715857×10−84 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−33 = 1.16e−10, so the sum moves off 1. But p0 is rounded to a multiple of that same 1.16e−10, and so is p0 − 1, against a gradient of 3.05e−8.

e−18 is below the smallest normal number, 0.0156, so it keeps only 13 significant bits.

e = 4, f = 33

standard−3.050081432×10−82 correct digits
TorchLean−3.046079655×10−83 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−34 = 5.82e−11, so the sum moves off 1. But p0 is rounded to a multiple of that same 5.82e−11, and so is p0 − 1, against a gradient of 3.05e−8.

e−18 is below the smallest normal number, 0.0156, so it keeps only 14 significant bits.

e = 4, f = 34

standard−3.050081432×10−82 correct digits
TorchLean−3.046079655×10−83 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−35 = 2.91e−11, so the sum moves off 1. But p0 is rounded to a multiple of that same 2.91e−11, and so is p0 − 1, against a gradient of 3.05e−8.

e−18 is below the smallest normal number, 0.0156, so it keeps only 15 significant bits.

e = 4, f = 35

standard−3.044260666×10−83 correct digits
TorchLean−3.045988706×10−85 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−36 = 1.46e−11, so the sum moves off 1. But p0 is rounded to a multiple of that same 1.46e−11, and so is p0 − 1, against a gradient of 3.05e−8.

e−18 is below the smallest normal number, 0.0156, so it keeps only 16 significant bits.

e = 4, f = 36

standard−3.047171049×10−83 correct digits
TorchLean−3.045988706×10−85 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−37 = 7.28e−12, so the sum moves off 1. But p0 is rounded to a multiple of that same 7.28e−12, and so is p0 − 1, against a gradient of 3.05e−8.

e−18 is below the smallest normal number, 0.0156, so it keeps only 17 significant bits.

e = 4, f = 37

standard−3.045715857×10−84 correct digits
TorchLean−3.045988706×10−85 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−38 = 3.64e−12, so the sum moves off 1. But p0 is rounded to a multiple of that same 3.64e−12, and so is p0 − 1, against a gradient of 3.05e−8.

e−18 is below the smallest normal number, 0.0156, so it keeps only 18 significant bits.

e = 4, f = 38

standard−3.045715857×10−84 correct digits
TorchLean−3.046000074×10−83 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−39 = 1.82e−12, so the sum moves off 1. But p0 is rounded to a multiple of that same 1.82e−12, and so is p0 − 1, against a gradient of 3.05e−8.

e−18 is below the smallest normal number, 0.0156, so it keeps only 19 significant bits.

e = 4, f = 39

standard−3.046079655×10−83 correct digits
TorchLean−3.045994390×10−86 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−40 = 9.09e−13, so the sum moves off 1. But p0 is rounded to a multiple of that same 9.09e−13, and so is p0 − 1, against a gradient of 3.05e−8.

e−18 is below the smallest normal number, 0.0156, so it keeps only 20 significant bits.

e = 4, f = 40

standard−3.046079655×10−83 correct digits
TorchLean−3.045997232×10−86 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−41 = 4.55e−13, so the sum moves off 1. But p0 is rounded to a multiple of that same 4.55e−13, and so is p0 − 1, against a gradient of 3.05e−8.

e−18 is below the smallest normal number, 0.0156, so it keeps only 21 significant bits.

e = 4, f = 41

standard−3.045988706×10−85 correct digits
TorchLean−3.045995811×10−88 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−42 = 2.27e−13, so the sum moves off 1. But p0 is rounded to a multiple of that same 2.27e−13, and so is p0 − 1, against a gradient of 3.05e−8.

e−18 is below the smallest normal number, 0.0156, so it keeps only 22 significant bits.

e = 4, f = 42

standard−3.045988706×10−85 correct digits
TorchLean−3.045995811×10−88 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−43 = 1.14e−13, so the sum moves off 1. But p0 is rounded to a multiple of that same 1.14e−13, and so is p0 − 1, against a gradient of 3.05e−8.

e−18 is below the smallest normal number, 0.0156, so it keeps only 23 significant bits.

e = 4, f = 43

standard−3.045988706×10−85 correct digits
TorchLean−3.045995811×10−88 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−44 = 5.68e−14, so the sum moves off 1. But p0 is rounded to a multiple of that same 5.68e−14, and so is p0 − 1, against a gradient of 3.05e−8.

e−18 is below the smallest normal number, 0.0156, so it keeps only 24 significant bits.

e = 4, f = 44

standard−3.046000074×10−83 correct digits
TorchLean−3.045995811×10−88 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−45 = 2.84e−14, so the sum moves off 1. But p0 is rounded to a multiple of that same 2.84e−14, and so is p0 − 1, against a gradient of 3.05e−8.

e−18 is below the smallest normal number, 0.0156, so it keeps only 25 significant bits.

e = 4, f = 45

standard−3.045994390×10−86 correct digits
TorchLean−3.045995900×10−87 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−46 = 1.42e−14, so the sum moves off 1. But p0 is rounded to a multiple of that same 1.42e−14, and so is p0 − 1, against a gradient of 3.05e−8.

e−18 is below the smallest normal number, 0.0156, so it keeps only 26 significant bits.

e = 4, f = 46

standard−3.045997232×10−86 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−47 = 7.11e−15, so the sum moves off 1. But p0 is rounded to a multiple of that same 7.11e−15, and so is p0 − 1, against a gradient of 3.05e−8.

e−18 is below the smallest normal number, 0.0156, so it keeps only 27 significant bits.

e = 4, f = 47

standard−3.045995811×10−88 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−48 = 3.55e−15, so the sum moves off 1. But p0 is rounded to a multiple of that same 3.55e−15, and so is p0 − 1, against a gradient of 3.05e−8.

e−18 is below the smallest normal number, 0.0156, so it keeps only 28 significant bits.

e = 4, f = 48

standard−3.045995633×10−87 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−49 = 1.78e−15, so the sum moves off 1. But p0 is rounded to a multiple of that same 1.78e−15, and so is p0 − 1, against a gradient of 3.05e−8.

e−18 is below the smallest normal number, 0.0156, so it keeps only 29 significant bits.

e = 4, f = 49

standard−3.045995722×10−87 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−50 = 8.88e−16, so the sum moves off 1. But p0 is rounded to a multiple of that same 8.88e−16, and so is p0 − 1, against a gradient of 3.05e−8.

e−18 is below the smallest normal number, 0.0156, so it keeps only 30 significant bits.

e = 4, f = 50

standard−3.045995900×10−87 correct digits
TorchLean−3.045995858×10−89 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−51 = 4.44e−16, so the sum moves off 1. But p0 is rounded to a multiple of that same 4.44e−16, and so is p0 − 1, against a gradient of 3.05e−8.

e−18 is below the smallest normal number, 0.0156, so it keeps only 31 significant bits.

e = 4, f = 51

standard−3.045995900×10−87 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−52 = 2.22e−16, so the sum moves off 1. But p0 is rounded to a multiple of that same 2.22e−16, and so is p0 − 1, against a gradient of 3.05e−8.

e−18 is below the smallest normal number, 0.0156, so it keeps only 32 significant bits.

e = 4, f = 52

standard−3.045995856×10−810 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−53 = 1.11e−16, so the sum moves off 1. But p0 is rounded to a multiple of that same 1.11e−16, and so is p0 − 1, against a gradient of 3.05e−8.

e−18 is below the smallest normal number, 0.0156, so it keeps only 33 significant bits.

e = 5, f = 1

standard0no correct digits
TorchLean0no correct digits

With 1 fraction bit the logit 9 is stored as 8, so both formulas compute the gradient for [8, −8, −8], not the exact value above. e−18 = 1.52e−8 is less than half a unit at 1, 2−2 = 0.25, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

e−18 is less than half the smallest positive number, 3.05e−5, so it rounds to 0 before anything is added.

e = 5, f = 2, E5M2

standard0no correct digits
TorchLean0no correct digits

With 2 fraction bits the logit 9 is stored as 8, so both formulas compute the gradient for [8, −8, −8], not the exact value above. e−18 = 1.52e−8 is less than half a unit at 1, 2−3 = 0.125, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

e−18 is less than half the smallest positive number, 1.53e−5, so it rounds to 0 before anything is added.

e = 5, f = 3

standard0no correct digits
TorchLean0no correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−4 = 0.0625, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

e−18 is less than half the smallest positive number, 7.63e−6, so it rounds to 0 before anything is added.

e = 5, f = 4

standard0no correct digits
TorchLean0no correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−5 = 0.0313, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

e−18 is less than half the smallest positive number, 3.81e−6, so it rounds to 0 before anything is added.

e = 5, f = 5

standard0no correct digits
TorchLean0no correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−6 = 0.0156, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

e−18 is less than half the smallest positive number, 1.91e−6, so it rounds to 0 before anything is added.

e = 5, f = 6

standard0no correct digits
TorchLean0no correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−7 = 0.00781, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

e−18 is less than half the smallest positive number, 9.54e−7, so it rounds to 0 before anything is added.

e = 5, f = 7

standard0no correct digits
TorchLean0no correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−8 = 0.00391, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

e−18 is less than half the smallest positive number, 4.77e−7, so it rounds to 0 before anything is added.

e = 5, f = 8

standard0no correct digits
TorchLean0no correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−9 = 0.00195, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

e−18 is less than half the smallest positive number, 2.38e−7, so it rounds to 0 before anything is added.

e = 5, f = 9

standard0no correct digits
TorchLean0no correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−10 = 9.77e−4, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

e−18 is less than half the smallest positive number, 1.19e−7, so it rounds to 0 before anything is added.

e = 5, f = 10, binary16

standard0no correct digits
TorchLean0no correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−11 = 4.88e−4, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

e−18 is less than half the smallest positive number, 5.96e−8, so it rounds to 0 before anything is added.

e = 5, f = 11

standard0no correct digits
TorchLean−5.960464478×10−8no correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−12 = 2.44e−4, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

e−18 is between half the smallest positive number and the smallest positive number, 2.98e−8, so it rounds up to 2.98e−8, about twice its value.

e = 5, f = 12

standard0no correct digits
TorchLean−2.980232239×10−8no correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−13 = 1.22e−4, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

e−18 is below the smallest normal number, 6.1e−5, so it keeps only 1 significant bit.

e = 5, f = 13

standard0no correct digits
TorchLean−2.980232239×10−8no correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−14 = 6.1e−5, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

e−18 is below the smallest normal number, 6.1e−5, so it keeps only 2 significant bits.

e = 5, f = 14

standard0no correct digits
TorchLean−2.980232239×10−8no correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−15 = 3.05e−5, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

e−18 is below the smallest normal number, 6.1e−5, so it keeps only 3 significant bits.

e = 5, f = 15

standard0no correct digits
TorchLean−2.980232239×10−8no correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−16 = 1.53e−5, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

e−18 is below the smallest normal number, 6.1e−5, so it keeps only 4 significant bits.

e = 5, f = 16

standard0no correct digits
TorchLean−2.980232239×10−8no correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−17 = 7.63e−6, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

e−18 is below the smallest normal number, 6.1e−5, so it keeps only 5 significant bits.

e = 5, f = 17

standard0no correct digits
TorchLean−3.073364496×10−82 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−18 = 3.81e−6, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

e−18 is below the smallest normal number, 6.1e−5, so it keeps only 6 significant bits.

e = 5, f = 18

standard0no correct digits
TorchLean−3.026798368×10−82 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−19 = 1.91e−6, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

e−18 is below the smallest normal number, 6.1e−5, so it keeps only 7 significant bits.

e = 5, f = 19

standard0no correct digits
TorchLean−3.050081432×10−82 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−20 = 9.54e−7, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

e−18 is below the smallest normal number, 6.1e−5, so it keeps only 8 significant bits.

e = 5, f = 20

standard0no correct digits
TorchLean−3.050081432×10−82 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−21 = 4.77e−7, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

e−18 is below the smallest normal number, 6.1e−5, so it keeps only 9 significant bits.

e = 5, f = 21

standard0no correct digits
TorchLean−3.044260666×10−83 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−22 = 2.38e−7, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

e−18 is below the smallest normal number, 6.1e−5, so it keeps only 10 significant bits.

e = 5, f = 22

standard0no correct digits
TorchLean−3.047171049×10−83 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−23 = 1.19e−7, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

e−18 is below the smallest normal number, 6.1e−5, so it keeps only 11 significant bits.

e = 5, f = 23

standard0no correct digits
TorchLean−3.045715857×10−84 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−24 = 5.96e−8, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

e−18 is below the smallest normal number, 6.1e−5, so it keeps only 12 significant bits.

e = 5, f = 24

standard0no correct digits
TorchLean−3.045715857×10−84 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−25 = 2.98e−8, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

e−18 is below the smallest normal number, 6.1e−5, so it keeps only 13 significant bits.

e = 5, f = 25

standard−5.960464478×10−8no correct digits
TorchLean−3.046079655×10−83 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−26 = 1.49e−8, so the sum moves off 1. But p0 is rounded to a multiple of that same 1.49e−8, and so is p0 − 1, against a gradient of 3.05e−8.

e−18 is below the smallest normal number, 6.1e−5, so it keeps only 14 significant bits.

e = 5, f = 26

standard−2.980232239×10−8no correct digits
TorchLean−3.046079655×10−83 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−27 = 7.45e−9, so the sum moves off 1. But p0 is rounded to a multiple of that same 7.45e−9, and so is p0 − 1, against a gradient of 3.05e−8.

e−18 is below the smallest normal number, 6.1e−5, so it keeps only 15 significant bits.

e = 5, f = 27

standard−2.980232239×10−8no correct digits
TorchLean−3.045988706×10−85 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−28 = 3.73e−9, so the sum moves off 1. But p0 is rounded to a multiple of that same 3.73e−9, and so is p0 − 1, against a gradient of 3.05e−8.

e−18 is below the smallest normal number, 6.1e−5, so it keeps only 16 significant bits.

e = 5, f = 28

standard−2.980232239×10−8no correct digits
TorchLean−3.045988706×10−85 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−29 = 1.86e−9, so the sum moves off 1. But p0 is rounded to a multiple of that same 1.86e−9, and so is p0 − 1, against a gradient of 3.05e−8.

e−18 is below the smallest normal number, 6.1e−5, so it keeps only 17 significant bits.

e = 5, f = 29

standard−2.980232239×10−8no correct digits
TorchLean−3.045988706×10−85 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−30 = 9.31e−10, so the sum moves off 1. But p0 is rounded to a multiple of that same 9.31e−10, and so is p0 − 1, against a gradient of 3.05e−8.

e−18 is below the smallest normal number, 6.1e−5, so it keeps only 18 significant bits.

e = 5, f = 30

standard−2.980232239×10−8no correct digits
TorchLean−3.046000074×10−83 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−31 = 4.66e−10, so the sum moves off 1. But p0 is rounded to a multiple of that same 4.66e−10, and so is p0 − 1, against a gradient of 3.05e−8.

e−18 is below the smallest normal number, 6.1e−5, so it keeps only 19 significant bits.

e = 5, f = 31

standard−3.073364496×10−82 correct digits
TorchLean−3.045994390×10−86 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−32 = 2.33e−10, so the sum moves off 1. But p0 is rounded to a multiple of that same 2.33e−10, and so is p0 − 1, against a gradient of 3.05e−8.

e−18 is below the smallest normal number, 6.1e−5, so it keeps only 20 significant bits.

e = 5, f = 32

standard−3.026798368×10−82 correct digits
TorchLean−3.045997232×10−86 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−33 = 1.16e−10, so the sum moves off 1. But p0 is rounded to a multiple of that same 1.16e−10, and so is p0 − 1, against a gradient of 3.05e−8.

e−18 is below the smallest normal number, 6.1e−5, so it keeps only 21 significant bits.

e = 5, f = 33

standard−3.050081432×10−82 correct digits
TorchLean−3.045995811×10−88 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−34 = 5.82e−11, so the sum moves off 1. But p0 is rounded to a multiple of that same 5.82e−11, and so is p0 − 1, against a gradient of 3.05e−8.

e−18 is below the smallest normal number, 6.1e−5, so it keeps only 22 significant bits.

e = 5, f = 34

standard−3.050081432×10−82 correct digits
TorchLean−3.045995811×10−88 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−35 = 2.91e−11, so the sum moves off 1. But p0 is rounded to a multiple of that same 2.91e−11, and so is p0 − 1, against a gradient of 3.05e−8.

e−18 is below the smallest normal number, 6.1e−5, so it keeps only 23 significant bits.

e = 5, f = 35

standard−3.044260666×10−83 correct digits
TorchLean−3.045995811×10−88 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−36 = 1.46e−11, so the sum moves off 1. But p0 is rounded to a multiple of that same 1.46e−11, and so is p0 − 1, against a gradient of 3.05e−8.

e−18 is below the smallest normal number, 6.1e−5, so it keeps only 24 significant bits.

e = 5, f = 36

standard−3.047171049×10−83 correct digits
TorchLean−3.045995811×10−88 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−37 = 7.28e−12, so the sum moves off 1. But p0 is rounded to a multiple of that same 7.28e−12, and so is p0 − 1, against a gradient of 3.05e−8.

e−18 is below the smallest normal number, 6.1e−5, so it keeps only 25 significant bits.

e = 5, f = 37

standard−3.045715857×10−84 correct digits
TorchLean−3.045995900×10−87 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−38 = 3.64e−12, so the sum moves off 1. But p0 is rounded to a multiple of that same 3.64e−12, and so is p0 − 1, against a gradient of 3.05e−8.

e−18 is below the smallest normal number, 6.1e−5, so it keeps only 26 significant bits.

e = 5, f = 38

standard−3.045715857×10−84 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−39 = 1.82e−12, so the sum moves off 1. But p0 is rounded to a multiple of that same 1.82e−12, and so is p0 − 1, against a gradient of 3.05e−8.

e−18 is below the smallest normal number, 6.1e−5, so it keeps only 27 significant bits.

e = 5, f = 39

standard−3.046079655×10−83 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−40 = 9.09e−13, so the sum moves off 1. But p0 is rounded to a multiple of that same 9.09e−13, and so is p0 − 1, against a gradient of 3.05e−8.

e−18 is below the smallest normal number, 6.1e−5, so it keeps only 28 significant bits.

e = 5, f = 40

standard−3.046079655×10−83 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−41 = 4.55e−13, so the sum moves off 1. But p0 is rounded to a multiple of that same 4.55e−13, and so is p0 − 1, against a gradient of 3.05e−8.

e−18 is below the smallest normal number, 6.1e−5, so it keeps only 29 significant bits.

e = 5, f = 41

standard−3.045988706×10−85 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−42 = 2.27e−13, so the sum moves off 1. But p0 is rounded to a multiple of that same 2.27e−13, and so is p0 − 1, against a gradient of 3.05e−8.

e−18 is below the smallest normal number, 6.1e−5, so it keeps only 30 significant bits.

e = 5, f = 42

standard−3.045988706×10−85 correct digits
TorchLean−3.045995858×10−89 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−43 = 1.14e−13, so the sum moves off 1. But p0 is rounded to a multiple of that same 1.14e−13, and so is p0 − 1, against a gradient of 3.05e−8.

e−18 is below the smallest normal number, 6.1e−5, so it keeps only 31 significant bits.

e = 5, f = 43

standard−3.045988706×10−85 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−44 = 5.68e−14, so the sum moves off 1. But p0 is rounded to a multiple of that same 5.68e−14, and so is p0 − 1, against a gradient of 3.05e−8.

e−18 is below the smallest normal number, 6.1e−5, so it keeps only 32 significant bits.

e = 5, f = 44

standard−3.046000074×10−83 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−45 = 2.84e−14, so the sum moves off 1. But p0 is rounded to a multiple of that same 2.84e−14, and so is p0 − 1, against a gradient of 3.05e−8.

e−18 is below the smallest normal number, 6.1e−5, so it keeps only 33 significant bits.

e = 5, f = 45

standard−3.045994390×10−86 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−46 = 1.42e−14, so the sum moves off 1. But p0 is rounded to a multiple of that same 1.42e−14, and so is p0 − 1, against a gradient of 3.05e−8.

e−18 is below the smallest normal number, 6.1e−5, so it keeps only 34 significant bits.

e = 5, f = 46

standard−3.045997232×10−86 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−47 = 7.11e−15, so the sum moves off 1. But p0 is rounded to a multiple of that same 7.11e−15, and so is p0 − 1, against a gradient of 3.05e−8.

e−18 is below the smallest normal number, 6.1e−5, so it keeps only 35 significant bits.

e = 5, f = 47

standard−3.045995811×10−88 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−48 = 3.55e−15, so the sum moves off 1. But p0 is rounded to a multiple of that same 3.55e−15, and so is p0 − 1, against a gradient of 3.05e−8.

e−18 is below the smallest normal number, 6.1e−5, so it keeps only 36 significant bits.

e = 5, f = 48

standard−3.045995633×10−87 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−49 = 1.78e−15, so the sum moves off 1. But p0 is rounded to a multiple of that same 1.78e−15, and so is p0 − 1, against a gradient of 3.05e−8.

e−18 is below the smallest normal number, 6.1e−5, so it keeps only 37 significant bits.

e = 5, f = 49

standard−3.045995722×10−87 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−50 = 8.88e−16, so the sum moves off 1. But p0 is rounded to a multiple of that same 8.88e−16, and so is p0 − 1, against a gradient of 3.05e−8.

e−18 is below the smallest normal number, 6.1e−5, so it keeps only 38 significant bits.

e = 5, f = 50

standard−3.045995900×10−87 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−51 = 4.44e−16, so the sum moves off 1. But p0 is rounded to a multiple of that same 4.44e−16, and so is p0 − 1, against a gradient of 3.05e−8.

e−18 is below the smallest normal number, 6.1e−5, so it keeps only 39 significant bits.

e = 5, f = 51

standard−3.045995900×10−87 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−52 = 2.22e−16, so the sum moves off 1. But p0 is rounded to a multiple of that same 2.22e−16, and so is p0 − 1, against a gradient of 3.05e−8.

e−18 is below the smallest normal number, 6.1e−5, so it keeps only 40 significant bits.

e = 5, f = 52

standard−3.045995856×10−810 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−53 = 1.11e−16, so the sum moves off 1. But p0 is rounded to a multiple of that same 1.11e−16, and so is p0 − 1, against a gradient of 3.05e−8.

e−18 is below the smallest normal number, 6.1e−5, so it keeps only 41 significant bits.

e = 6, f = 1

standard0no correct digits
TorchLean−2.384185791×10−7no correct digits

With 1 fraction bit the logit 9 is stored as 8, so both formulas compute the gradient for [8, −8, −8], not the exact value above. e−18 = 1.52e−8 is less than half a unit at 1, 2−2 = 0.25, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 2 significant bits.

e = 6, f = 2

standard0no correct digits
TorchLean−2.384185791×10−7no correct digits

With 2 fraction bits the logit 9 is stored as 8, so both formulas compute the gradient for [8, −8, −8], not the exact value above. e−18 = 1.52e−8 is less than half a unit at 1, 2−3 = 0.125, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 3 significant bits.

e = 6, f = 3

standard0no correct digits
TorchLean−2.980232239×10−8no correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−4 = 0.0625, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 4 significant bits.

e = 6, f = 4

standard0no correct digits
TorchLean−2.980232239×10−8no correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−5 = 0.0313, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 5 significant bits.

e = 6, f = 5

standard0no correct digits
TorchLean−3.073364496×10−82 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−6 = 0.0156, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 6 significant bits.

e = 6, f = 6

standard0no correct digits
TorchLean−3.026798368×10−82 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−7 = 0.00781, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 7 significant bits.

e = 6, f = 7

standard0no correct digits
TorchLean−3.050081432×10−82 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−8 = 0.00391, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 8 significant bits.

e = 6, f = 8

standard0no correct digits
TorchLean−3.050081432×10−82 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−9 = 0.00195, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 9 significant bits.

e = 6, f = 9

standard0no correct digits
TorchLean−3.044260666×10−83 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−10 = 9.77e−4, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 10 significant bits.

e = 6, f = 10

standard0no correct digits
TorchLean−3.047171049×10−83 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−11 = 4.88e−4, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 11 significant bits.

e = 6, f = 11

standard0no correct digits
TorchLean−3.045715857×10−84 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−12 = 2.44e−4, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 12 significant bits.

e = 6, f = 12

standard0no correct digits
TorchLean−3.045715857×10−84 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−13 = 1.22e−4, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 13 significant bits.

e = 6, f = 13

standard0no correct digits
TorchLean−3.046079655×10−83 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−14 = 6.1e−5, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 14 significant bits.

e = 6, f = 14

standard0no correct digits
TorchLean−3.046079655×10−83 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−15 = 3.05e−5, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 15 significant bits.

e = 6, f = 15

standard0no correct digits
TorchLean−3.045988706×10−85 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−16 = 1.53e−5, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 16 significant bits.

e = 6, f = 16

standard0no correct digits
TorchLean−3.045988706×10−85 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−17 = 7.63e−6, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 17 significant bits.

e = 6, f = 17

standard0no correct digits
TorchLean−3.045988706×10−85 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−18 = 3.81e−6, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 18 significant bits.

e = 6, f = 18

standard0no correct digits
TorchLean−3.046000074×10−83 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−19 = 1.91e−6, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 19 significant bits.

e = 6, f = 19

standard0no correct digits
TorchLean−3.045994390×10−86 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−20 = 9.54e−7, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 20 significant bits.

e = 6, f = 20

standard0no correct digits
TorchLean−3.045997232×10−86 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−21 = 4.77e−7, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 21 significant bits.

e = 6, f = 21

standard0no correct digits
TorchLean−3.045995811×10−88 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−22 = 2.38e−7, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 22 significant bits.

e = 6, f = 22

standard0no correct digits
TorchLean−3.045995811×10−88 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−23 = 1.19e−7, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 23 significant bits.

e = 6, f = 23

standard0no correct digits
TorchLean−3.045995811×10−88 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−24 = 5.96e−8, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 24 significant bits.

e = 6, f = 24

standard0no correct digits
TorchLean−3.045995989×10−87 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−25 = 2.98e−8, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 25 significant bits.

e = 6, f = 25

standard−5.960464478×10−8no correct digits
TorchLean−3.045995811×10−88 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−26 = 1.49e−8, so the sum moves off 1. But p0 is rounded to a multiple of that same 1.49e−8, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 26 significant bits.

e = 6, f = 26

standard−2.980232239×10−8no correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−27 = 7.45e−9, so the sum moves off 1. But p0 is rounded to a multiple of that same 7.45e−9, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 27 significant bits.

e = 6, f = 27

standard−2.980232239×10−8no correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−28 = 3.73e−9, so the sum moves off 1. But p0 is rounded to a multiple of that same 3.73e−9, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 28 significant bits.

e = 6, f = 28

standard−2.980232239×10−8no correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−29 = 1.86e−9, so the sum moves off 1. But p0 is rounded to a multiple of that same 1.86e−9, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 29 significant bits.

e = 6, f = 29

standard−2.980232239×10−8no correct digits
TorchLean−3.045995861×10−88 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−30 = 9.31e−10, so the sum moves off 1. But p0 is rounded to a multiple of that same 9.31e−10, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 30 significant bits.

e = 6, f = 30

standard−2.980232239×10−8no correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−31 = 4.66e−10, so the sum moves off 1. But p0 is rounded to a multiple of that same 4.66e−10, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 31 significant bits.

e = 6, f = 31

standard−3.073364496×10−82 correct digits
TorchLean−3.045995857×10−89 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−32 = 2.33e−10, so the sum moves off 1. But p0 is rounded to a multiple of that same 2.33e−10, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 32 significant bits.

e = 6, f = 32

standard−3.026798368×10−82 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−33 = 1.16e−10, so the sum moves off 1. But p0 is rounded to a multiple of that same 1.16e−10, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 33 significant bits.

e = 6, f = 33

standard−3.050081432×10−82 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−34 = 5.82e−11, so the sum moves off 1. But p0 is rounded to a multiple of that same 5.82e−11, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 34 significant bits.

e = 6, f = 34

standard−3.050081432×10−82 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−35 = 2.91e−11, so the sum moves off 1. But p0 is rounded to a multiple of that same 2.91e−11, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 35 significant bits.

e = 6, f = 35

standard−3.044260666×10−83 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−36 = 1.46e−11, so the sum moves off 1. But p0 is rounded to a multiple of that same 1.46e−11, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 36 significant bits.

e = 6, f = 36

standard−3.047171049×10−83 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−37 = 7.28e−12, so the sum moves off 1. But p0 is rounded to a multiple of that same 7.28e−12, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 37 significant bits.

e = 6, f = 37

standard−3.045715857×10−84 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−38 = 3.64e−12, so the sum moves off 1. But p0 is rounded to a multiple of that same 3.64e−12, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 38 significant bits.

e = 6, f = 38

standard−3.045715857×10−84 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−39 = 1.82e−12, so the sum moves off 1. But p0 is rounded to a multiple of that same 1.82e−12, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 39 significant bits.

e = 6, f = 39

standard−3.046079655×10−83 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−40 = 9.09e−13, so the sum moves off 1. But p0 is rounded to a multiple of that same 9.09e−13, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 40 significant bits.

e = 6, f = 40

standard−3.046079655×10−83 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−41 = 4.55e−13, so the sum moves off 1. But p0 is rounded to a multiple of that same 4.55e−13, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 41 significant bits.

e = 6, f = 41

standard−3.045988706×10−85 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−42 = 2.27e−13, so the sum moves off 1. But p0 is rounded to a multiple of that same 2.27e−13, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 42 significant bits.

e = 6, f = 42

standard−3.045988706×10−85 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−43 = 1.14e−13, so the sum moves off 1. But p0 is rounded to a multiple of that same 1.14e−13, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 43 significant bits.

e = 6, f = 43

standard−3.045988706×10−85 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−44 = 5.68e−14, so the sum moves off 1. But p0 is rounded to a multiple of that same 5.68e−14, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 44 significant bits.

e = 6, f = 44

standard−3.046000074×10−83 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−45 = 2.84e−14, so the sum moves off 1. But p0 is rounded to a multiple of that same 2.84e−14, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 45 significant bits.

e = 6, f = 45

standard−3.045994390×10−86 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−46 = 1.42e−14, so the sum moves off 1. But p0 is rounded to a multiple of that same 1.42e−14, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 46 significant bits.

e = 6, f = 46

standard−3.045997232×10−86 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−47 = 7.11e−15, so the sum moves off 1. But p0 is rounded to a multiple of that same 7.11e−15, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 47 significant bits.

e = 6, f = 47

standard−3.045995811×10−88 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−48 = 3.55e−15, so the sum moves off 1. But p0 is rounded to a multiple of that same 3.55e−15, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 48 significant bits.

e = 6, f = 48

standard−3.045995633×10−87 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−49 = 1.78e−15, so the sum moves off 1. But p0 is rounded to a multiple of that same 1.78e−15, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 49 significant bits.

e = 6, f = 49

standard−3.045995722×10−87 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−50 = 8.88e−16, so the sum moves off 1. But p0 is rounded to a multiple of that same 8.88e−16, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 50 significant bits.

e = 6, f = 50

standard−3.045995900×10−87 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−51 = 4.44e−16, so the sum moves off 1. But p0 is rounded to a multiple of that same 4.44e−16, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 51 significant bits.

e = 6, f = 51

standard−3.045995900×10−87 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−52 = 2.22e−16, so the sum moves off 1. But p0 is rounded to a multiple of that same 2.22e−16, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 52 significant bits.

e = 6, f = 52

standard−3.045995856×10−810 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−53 = 1.11e−16, so the sum moves off 1. But p0 is rounded to a multiple of that same 1.11e−16, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 53 significant bits.

e = 8, f = 1

standard0no correct digits
TorchLean−2.384185791×10−7no correct digits

With 1 fraction bit the logit 9 is stored as 8, so both formulas compute the gradient for [8, −8, −8], not the exact value above. e−18 = 1.52e−8 is less than half a unit at 1, 2−2 = 0.25, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 2 significant bits.

e = 8, f = 2

standard0no correct digits
TorchLean−2.384185791×10−7no correct digits

With 2 fraction bits the logit 9 is stored as 8, so both formulas compute the gradient for [8, −8, −8], not the exact value above. e−18 = 1.52e−8 is less than half a unit at 1, 2−3 = 0.125, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 3 significant bits.

e = 8, f = 3

standard0no correct digits
TorchLean−2.980232239×10−8no correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−4 = 0.0625, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 4 significant bits.

e = 8, f = 4

standard0no correct digits
TorchLean−2.980232239×10−8no correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−5 = 0.0313, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 5 significant bits.

e = 8, f = 5

standard0no correct digits
TorchLean−3.073364496×10−82 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−6 = 0.0156, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 6 significant bits.

e = 8, f = 6

standard0no correct digits
TorchLean−3.026798368×10−82 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−7 = 0.00781, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 7 significant bits.

e = 8, f = 7, bfloat16

standard0no correct digits
TorchLean−3.050081432×10−82 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−8 = 0.00391, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 8 significant bits.

e = 8, f = 8

standard0no correct digits
TorchLean−3.050081432×10−82 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−9 = 0.00195, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 9 significant bits.

e = 8, f = 9

standard0no correct digits
TorchLean−3.044260666×10−83 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−10 = 9.77e−4, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 10 significant bits.

e = 8, f = 10, tf32

standard0no correct digits
TorchLean−3.047171049×10−83 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−11 = 4.88e−4, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 11 significant bits.

e = 8, f = 11

standard0no correct digits
TorchLean−3.045715857×10−84 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−12 = 2.44e−4, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 12 significant bits.

e = 8, f = 12

standard0no correct digits
TorchLean−3.045715857×10−84 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−13 = 1.22e−4, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 13 significant bits.

e = 8, f = 13

standard0no correct digits
TorchLean−3.046079655×10−83 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−14 = 6.1e−5, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 14 significant bits.

e = 8, f = 14

standard0no correct digits
TorchLean−3.046079655×10−83 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−15 = 3.05e−5, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 15 significant bits.

e = 8, f = 15

standard0no correct digits
TorchLean−3.045988706×10−85 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−16 = 1.53e−5, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 16 significant bits.

e = 8, f = 16

standard0no correct digits
TorchLean−3.045988706×10−85 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−17 = 7.63e−6, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 17 significant bits.

e = 8, f = 17

standard0no correct digits
TorchLean−3.045988706×10−85 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−18 = 3.81e−6, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 18 significant bits.

e = 8, f = 18

standard0no correct digits
TorchLean−3.046000074×10−83 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−19 = 1.91e−6, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 19 significant bits.

e = 8, f = 19

standard0no correct digits
TorchLean−3.045994390×10−86 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−20 = 9.54e−7, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 20 significant bits.

e = 8, f = 20

standard0no correct digits
TorchLean−3.045997232×10−86 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−21 = 4.77e−7, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 21 significant bits.

e = 8, f = 21

standard0no correct digits
TorchLean−3.045995811×10−88 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−22 = 2.38e−7, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 22 significant bits.

e = 8, f = 22

standard0no correct digits
TorchLean−3.045995811×10−88 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−23 = 1.19e−7, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 23 significant bits.

e = 8, f = 23, binary32

standard0no correct digits
TorchLean−3.045995811×10−88 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−24 = 5.96e−8, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 24 significant bits.

e = 8, f = 24

standard0no correct digits
TorchLean−3.045995989×10−87 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−25 = 2.98e−8, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 25 significant bits.

e = 8, f = 25

standard−5.960464478×10−8no correct digits
TorchLean−3.045995811×10−88 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−26 = 1.49e−8, so the sum moves off 1. But p0 is rounded to a multiple of that same 1.49e−8, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 26 significant bits.

e = 8, f = 26

standard−2.980232239×10−8no correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−27 = 7.45e−9, so the sum moves off 1. But p0 is rounded to a multiple of that same 7.45e−9, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 27 significant bits.

e = 8, f = 27

standard−2.980232239×10−8no correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−28 = 3.73e−9, so the sum moves off 1. But p0 is rounded to a multiple of that same 3.73e−9, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 28 significant bits.

e = 8, f = 28

standard−2.980232239×10−8no correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−29 = 1.86e−9, so the sum moves off 1. But p0 is rounded to a multiple of that same 1.86e−9, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 29 significant bits.

e = 8, f = 29

standard−2.980232239×10−8no correct digits
TorchLean−3.045995861×10−88 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−30 = 9.31e−10, so the sum moves off 1. But p0 is rounded to a multiple of that same 9.31e−10, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 30 significant bits.

e = 8, f = 30

standard−2.980232239×10−8no correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−31 = 4.66e−10, so the sum moves off 1. But p0 is rounded to a multiple of that same 4.66e−10, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 31 significant bits.

e = 8, f = 31

standard−3.073364496×10−82 correct digits
TorchLean−3.045995857×10−89 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−32 = 2.33e−10, so the sum moves off 1. But p0 is rounded to a multiple of that same 2.33e−10, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 32 significant bits.

e = 8, f = 32

standard−3.026798368×10−82 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−33 = 1.16e−10, so the sum moves off 1. But p0 is rounded to a multiple of that same 1.16e−10, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 33 significant bits.

e = 8, f = 33

standard−3.050081432×10−82 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−34 = 5.82e−11, so the sum moves off 1. But p0 is rounded to a multiple of that same 5.82e−11, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 34 significant bits.

e = 8, f = 34

standard−3.050081432×10−82 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−35 = 2.91e−11, so the sum moves off 1. But p0 is rounded to a multiple of that same 2.91e−11, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 35 significant bits.

e = 8, f = 35

standard−3.044260666×10−83 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−36 = 1.46e−11, so the sum moves off 1. But p0 is rounded to a multiple of that same 1.46e−11, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 36 significant bits.

e = 8, f = 36

standard−3.047171049×10−83 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−37 = 7.28e−12, so the sum moves off 1. But p0 is rounded to a multiple of that same 7.28e−12, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 37 significant bits.

e = 8, f = 37

standard−3.045715857×10−84 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−38 = 3.64e−12, so the sum moves off 1. But p0 is rounded to a multiple of that same 3.64e−12, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 38 significant bits.

e = 8, f = 38

standard−3.045715857×10−84 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−39 = 1.82e−12, so the sum moves off 1. But p0 is rounded to a multiple of that same 1.82e−12, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 39 significant bits.

e = 8, f = 39

standard−3.046079655×10−83 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−40 = 9.09e−13, so the sum moves off 1. But p0 is rounded to a multiple of that same 9.09e−13, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 40 significant bits.

e = 8, f = 40

standard−3.046079655×10−83 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−41 = 4.55e−13, so the sum moves off 1. But p0 is rounded to a multiple of that same 4.55e−13, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 41 significant bits.

e = 8, f = 41

standard−3.045988706×10−85 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−42 = 2.27e−13, so the sum moves off 1. But p0 is rounded to a multiple of that same 2.27e−13, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 42 significant bits.

e = 8, f = 42

standard−3.045988706×10−85 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−43 = 1.14e−13, so the sum moves off 1. But p0 is rounded to a multiple of that same 1.14e−13, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 43 significant bits.

e = 8, f = 43

standard−3.045988706×10−85 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−44 = 5.68e−14, so the sum moves off 1. But p0 is rounded to a multiple of that same 5.68e−14, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 44 significant bits.

e = 8, f = 44

standard−3.046000074×10−83 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−45 = 2.84e−14, so the sum moves off 1. But p0 is rounded to a multiple of that same 2.84e−14, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 45 significant bits.

e = 8, f = 45

standard−3.045994390×10−86 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−46 = 1.42e−14, so the sum moves off 1. But p0 is rounded to a multiple of that same 1.42e−14, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 46 significant bits.

e = 8, f = 46

standard−3.045997232×10−86 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−47 = 7.11e−15, so the sum moves off 1. But p0 is rounded to a multiple of that same 7.11e−15, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 47 significant bits.

e = 8, f = 47

standard−3.045995811×10−88 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−48 = 3.55e−15, so the sum moves off 1. But p0 is rounded to a multiple of that same 3.55e−15, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 48 significant bits.

e = 8, f = 48

standard−3.045995633×10−87 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−49 = 1.78e−15, so the sum moves off 1. But p0 is rounded to a multiple of that same 1.78e−15, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 49 significant bits.

e = 8, f = 49

standard−3.045995722×10−87 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−50 = 8.88e−16, so the sum moves off 1. But p0 is rounded to a multiple of that same 8.88e−16, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 50 significant bits.

e = 8, f = 50

standard−3.045995900×10−87 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−51 = 4.44e−16, so the sum moves off 1. But p0 is rounded to a multiple of that same 4.44e−16, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 51 significant bits.

e = 8, f = 51

standard−3.045995900×10−87 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−52 = 2.22e−16, so the sum moves off 1. But p0 is rounded to a multiple of that same 2.22e−16, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 52 significant bits.

e = 8, f = 52

standard−3.045995856×10−810 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−53 = 1.11e−16, so the sum moves off 1. But p0 is rounded to a multiple of that same 1.11e−16, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 53 significant bits.

e = 11, f = 1

standard0no correct digits
TorchLean−2.384185791×10−7no correct digits

With 1 fraction bit the logit 9 is stored as 8, so both formulas compute the gradient for [8, −8, −8], not the exact value above. e−18 = 1.52e−8 is less than half a unit at 1, 2−2 = 0.25, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 2 significant bits.

e = 11, f = 2

standard0no correct digits
TorchLean−2.384185791×10−7no correct digits

With 2 fraction bits the logit 9 is stored as 8, so both formulas compute the gradient for [8, −8, −8], not the exact value above. e−18 = 1.52e−8 is less than half a unit at 1, 2−3 = 0.125, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 3 significant bits.

e = 11, f = 3

standard0no correct digits
TorchLean−2.980232239×10−8no correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−4 = 0.0625, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 4 significant bits.

e = 11, f = 4

standard0no correct digits
TorchLean−2.980232239×10−8no correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−5 = 0.0313, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 5 significant bits.

e = 11, f = 5

standard0no correct digits
TorchLean−3.073364496×10−82 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−6 = 0.0156, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 6 significant bits.

e = 11, f = 6

standard0no correct digits
TorchLean−3.026798368×10−82 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−7 = 0.00781, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 7 significant bits.

e = 11, f = 7

standard0no correct digits
TorchLean−3.050081432×10−82 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−8 = 0.00391, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 8 significant bits.

e = 11, f = 8

standard0no correct digits
TorchLean−3.050081432×10−82 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−9 = 0.00195, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 9 significant bits.

e = 11, f = 9

standard0no correct digits
TorchLean−3.044260666×10−83 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−10 = 9.77e−4, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 10 significant bits.

e = 11, f = 10

standard0no correct digits
TorchLean−3.047171049×10−83 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−11 = 4.88e−4, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 11 significant bits.

e = 11, f = 11

standard0no correct digits
TorchLean−3.045715857×10−84 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−12 = 2.44e−4, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 12 significant bits.

e = 11, f = 12

standard0no correct digits
TorchLean−3.045715857×10−84 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−13 = 1.22e−4, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 13 significant bits.

e = 11, f = 13

standard0no correct digits
TorchLean−3.046079655×10−83 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−14 = 6.1e−5, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 14 significant bits.

e = 11, f = 14

standard0no correct digits
TorchLean−3.046079655×10−83 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−15 = 3.05e−5, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 15 significant bits.

e = 11, f = 15

standard0no correct digits
TorchLean−3.045988706×10−85 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−16 = 1.53e−5, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 16 significant bits.

e = 11, f = 16

standard0no correct digits
TorchLean−3.045988706×10−85 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−17 = 7.63e−6, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 17 significant bits.

e = 11, f = 17

standard0no correct digits
TorchLean−3.045988706×10−85 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−18 = 3.81e−6, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 18 significant bits.

e = 11, f = 18

standard0no correct digits
TorchLean−3.046000074×10−83 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−19 = 1.91e−6, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 19 significant bits.

e = 11, f = 19

standard0no correct digits
TorchLean−3.045994390×10−86 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−20 = 9.54e−7, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 20 significant bits.

e = 11, f = 20

standard0no correct digits
TorchLean−3.045997232×10−86 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−21 = 4.77e−7, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 21 significant bits.

e = 11, f = 21

standard0no correct digits
TorchLean−3.045995811×10−88 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−22 = 2.38e−7, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 22 significant bits.

e = 11, f = 22

standard0no correct digits
TorchLean−3.045995811×10−88 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−23 = 1.19e−7, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 23 significant bits.

e = 11, f = 23

standard0no correct digits
TorchLean−3.045995811×10−88 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−24 = 5.96e−8, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 24 significant bits.

e = 11, f = 24

standard0no correct digits
TorchLean−3.045995989×10−87 correct digits

e−18 = 1.52e−8 is less than half a unit at 1, 2−25 = 2.98e−8, so each addition to the running sum rounds back to 1 and p0 − 1 is 0.

The two small exponentials are added to each other, not to 1, so each keeps its 25 significant bits.

e = 11, f = 25

standard−5.960464478×10−8no correct digits
TorchLean−3.045995811×10−88 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−26 = 1.49e−8, so the sum moves off 1. But p0 is rounded to a multiple of that same 1.49e−8, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 26 significant bits.

e = 11, f = 26

standard−2.980232239×10−8no correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−27 = 7.45e−9, so the sum moves off 1. But p0 is rounded to a multiple of that same 7.45e−9, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 27 significant bits.

e = 11, f = 27

standard−2.980232239×10−8no correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−28 = 3.73e−9, so the sum moves off 1. But p0 is rounded to a multiple of that same 3.73e−9, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 28 significant bits.

e = 11, f = 28

standard−2.980232239×10−8no correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−29 = 1.86e−9, so the sum moves off 1. But p0 is rounded to a multiple of that same 1.86e−9, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 29 significant bits.

e = 11, f = 29

standard−2.980232239×10−8no correct digits
TorchLean−3.045995861×10−88 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−30 = 9.31e−10, so the sum moves off 1. But p0 is rounded to a multiple of that same 9.31e−10, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 30 significant bits.

e = 11, f = 30

standard−2.980232239×10−8no correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−31 = 4.66e−10, so the sum moves off 1. But p0 is rounded to a multiple of that same 4.66e−10, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 31 significant bits.

e = 11, f = 31

standard−3.073364496×10−82 correct digits
TorchLean−3.045995857×10−89 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−32 = 2.33e−10, so the sum moves off 1. But p0 is rounded to a multiple of that same 2.33e−10, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 32 significant bits.

e = 11, f = 32

standard−3.026798368×10−82 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−33 = 1.16e−10, so the sum moves off 1. But p0 is rounded to a multiple of that same 1.16e−10, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 33 significant bits.

e = 11, f = 33

standard−3.050081432×10−82 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−34 = 5.82e−11, so the sum moves off 1. But p0 is rounded to a multiple of that same 5.82e−11, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 34 significant bits.

e = 11, f = 34

standard−3.050081432×10−82 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−35 = 2.91e−11, so the sum moves off 1. But p0 is rounded to a multiple of that same 2.91e−11, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 35 significant bits.

e = 11, f = 35

standard−3.044260666×10−83 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−36 = 1.46e−11, so the sum moves off 1. But p0 is rounded to a multiple of that same 1.46e−11, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 36 significant bits.

e = 11, f = 36

standard−3.047171049×10−83 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−37 = 7.28e−12, so the sum moves off 1. But p0 is rounded to a multiple of that same 7.28e−12, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 37 significant bits.

e = 11, f = 37

standard−3.045715857×10−84 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−38 = 3.64e−12, so the sum moves off 1. But p0 is rounded to a multiple of that same 3.64e−12, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 38 significant bits.

e = 11, f = 38

standard−3.045715857×10−84 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−39 = 1.82e−12, so the sum moves off 1. But p0 is rounded to a multiple of that same 1.82e−12, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 39 significant bits.

e = 11, f = 39

standard−3.046079655×10−83 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−40 = 9.09e−13, so the sum moves off 1. But p0 is rounded to a multiple of that same 9.09e−13, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 40 significant bits.

e = 11, f = 40

standard−3.046079655×10−83 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−41 = 4.55e−13, so the sum moves off 1. But p0 is rounded to a multiple of that same 4.55e−13, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 41 significant bits.

e = 11, f = 41

standard−3.045988706×10−85 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−42 = 2.27e−13, so the sum moves off 1. But p0 is rounded to a multiple of that same 2.27e−13, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 42 significant bits.

e = 11, f = 42

standard−3.045988706×10−85 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−43 = 1.14e−13, so the sum moves off 1. But p0 is rounded to a multiple of that same 1.14e−13, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 43 significant bits.

e = 11, f = 43

standard−3.045988706×10−85 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−44 = 5.68e−14, so the sum moves off 1. But p0 is rounded to a multiple of that same 5.68e−14, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 44 significant bits.

e = 11, f = 44

standard−3.046000074×10−83 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−45 = 2.84e−14, so the sum moves off 1. But p0 is rounded to a multiple of that same 2.84e−14, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 45 significant bits.

e = 11, f = 45

standard−3.045994390×10−86 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−46 = 1.42e−14, so the sum moves off 1. But p0 is rounded to a multiple of that same 1.42e−14, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 46 significant bits.

e = 11, f = 46

standard−3.045997232×10−86 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−47 = 7.11e−15, so the sum moves off 1. But p0 is rounded to a multiple of that same 7.11e−15, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 47 significant bits.

e = 11, f = 47

standard−3.045995811×10−88 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−48 = 3.55e−15, so the sum moves off 1. But p0 is rounded to a multiple of that same 3.55e−15, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 48 significant bits.

e = 11, f = 48

standard−3.045995633×10−87 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−49 = 1.78e−15, so the sum moves off 1. But p0 is rounded to a multiple of that same 1.78e−15, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 49 significant bits.

e = 11, f = 49

standard−3.045995722×10−87 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−50 = 8.88e−16, so the sum moves off 1. But p0 is rounded to a multiple of that same 8.88e−16, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 50 significant bits.

e = 11, f = 50

standard−3.045995900×10−87 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−51 = 4.44e−16, so the sum moves off 1. But p0 is rounded to a multiple of that same 4.44e−16, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 51 significant bits.

e = 11, f = 51

standard−3.045995900×10−87 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−52 = 2.22e−16, so the sum moves off 1. But p0 is rounded to a multiple of that same 2.22e−16, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 52 significant bits.

e = 11, f = 52, binary64

standard−3.045995856×10−810 correct digits
TorchLean−3.045995856×10−810 correct digits

e−18 = 1.52e−8 is more than half a unit at 1, 2−53 = 1.11e−16, so the sum moves off 1. But p0 is rounded to a multiple of that same 1.11e−16, and so is p0 − 1, against a gradient of 3.05e−8.

The two small exponentials are added to each other, not to 1, so each keeps its 53 significant bits.

Figure 5. How many fraction bits preserve the gradient?Both formulas use the softmax input from Figure 2. Green digits agree with the real-valued reference; red digits begin at the first disagreement. More fraction bits can repair precision loss, but a narrow exponent range can still erase a small intermediate.
Arithmetic and reference values

The target-logit gradient is evaluated at logits [9, -9, -9], with class 0 as the target. These are the same Lean results used in Figure 4, with mpmath references at 256 bits.

I wouldn't pick one formula and assume it's the right choice at every precision. We need to consider the format, input range, intermediate precision and operation order together, and check the numerical guarantees for the implementation we actually use.

Case study II: a transformer block

For the final case study, I wanted to see what happens when these errors move through a model rather than appearing in an isolated operator. Attention combines matrix products, softmax, and weighted sums; in our JAX tests, even float64 attention computed its softmax in float32 on both devices, with relative output errors as large as \(8.6\times10^{-8}\). MLX and CPU ONNX Runtime showed similar errors, though we did not isolate their causes. To trace the calculation more closely, I built a small transformer block using GPT-2's layout: three tokens of width 4, causal attention, a width 8 MLP with tanh GELU, and five output classes. Class 2 is the target, with a loss over the real numbers of about \(2.9\times10^{-8}\). Lean recorded 362 intermediate values in each of 12 formats. The visualization follows the errors from the first layer normalization all the way to the loss gradient.

Format
Show the forward pass up to
relative error≤ 1e−14≤ 1e−11≤ 1e−8≤ 1e−5≤ 1e−3≤ 0.1> 0.1a wrong 00, and that is the exact value rounded

binary64, up to and including the first LayerNorm: the largest relative error is 1.4e−16, at normalized. No value is a wrong 0.

binary64, up to and including the attention: the largest relative error is 4.8e−15, at weights · v. No value is a wrong 0.

binary64, up to and including the first residual: the largest relative error is 4.8e−15, at weights · v. No value is a wrong 0.

binary64, up to and including the second LayerNorm: the largest relative error is 4.8e−15, at weights · v. No value is a wrong 0.

binary64, up to and including the MLP: the largest relative error is 4.8e−15, at weights · v. No value is a wrong 0.

binary64, up to and including the second residual: the largest relative error is 4.8e−15, at weights · v. No value is a wrong 0.

binary64, up to and including the final LayerNorm and the logits: the largest relative error is 4.8e−15, at weights · v. No value is a wrong 0.

binary64, up to and including both cross-entropy heads: the largest relative error is 1.2e−9, at gradient. No value is a wrong 0. Target gradient: standard −2.9058e−8 (relative error 1.2e−9), TorchLean −2.9058e−8 (relative error 2e−15); exact −2.906e−8.

posit32, up to and including the first LayerNorm: the largest relative error is 5.8e−9, at normalized. No value is a wrong 0.

posit32, up to and including the attention: the largest relative error is 1.7e−7, at weights · v. No value is a wrong 0.

posit32, up to and including the first residual: the largest relative error is 1.7e−7, at weights · v. No value is a wrong 0.

posit32, up to and including the second LayerNorm: the largest relative error is 1.7e−7, at weights · v. No value is a wrong 0.

posit32, up to and including the MLP: the largest relative error is 1.7e−7, at weights · v. No value is a wrong 0.

posit32, up to and including the second residual: the largest relative error is 1.7e−7, at weights · v. No value is a wrong 0.

posit32, up to and including the final LayerNorm and the logits: the largest relative error is 3e−7, at logits. No value is a wrong 0.

posit32, up to and including both cross-entropy heads: the largest relative error is 0.026, at gradient. No value is a wrong 0. Target gradient: standard −2.9802e−8 (relative error 0.026), TorchLean −2.9058e−8 (relative error 1.4e−8); exact −2.906e−8.

binary32, up to and including the first LayerNorm: the largest relative error is 7.8e−8, at normalized. No value is a wrong 0.

binary32, up to and including the attention: the largest relative error is 1.7e−6, at weights · v. No value is a wrong 0.

binary32, up to and including the first residual: the largest relative error is 1.7e−6, at weights · v. No value is a wrong 0.

binary32, up to and including the second LayerNorm: the largest relative error is 1.7e−6, at weights · v. No value is a wrong 0.

binary32, up to and including the MLP: the largest relative error is 4e−6, at 1 + tanh z. No value is a wrong 0.

binary32, up to and including the second residual: the largest relative error is 4e−6, at 1 + tanh z. No value is a wrong 0.

binary32, up to and including the final LayerNorm and the logits: the largest relative error is 4e−6, at 1 + tanh z. No value is a wrong 0.

binary32, up to and including both cross-entropy heads: the largest relative error is 4e−6, at 1 + tanh z. 4 values are 0 where the exact value rounded to binary32 is not (log sum, log p₂, loss, gradient). Target gradient: standard 0, TorchLean −2.9058e−8 (relative error 1.5e−6); exact −2.906e−8.

posit16, up to and including the first LayerNorm: the largest relative error is 3.5e−4, at normalized. No value is a wrong 0.

posit16, up to and including the attention: the largest relative error is 0.0098, at v. No value is a wrong 0.

posit16, up to and including the first residual: the largest relative error is 0.0098, at v. No value is a wrong 0.

posit16, up to and including the second LayerNorm: the largest relative error is 0.0098, at v. No value is a wrong 0.

posit16, up to and including the MLP: the largest relative error is 0.0098, at v. No value is a wrong 0.

posit16, up to and including the second residual: the largest relative error is 0.0098, at v. No value is a wrong 0.

posit16, up to and including the final LayerNorm and the logits: the largest relative error is 0.0098, at v. No value is a wrong 0.

posit16, up to and including both cross-entropy heads: the largest relative error is 0.014, at gradient. 4 values are 0 where the exact value rounded to posit16 is not (log sum, log p₂, loss, gradient). Target gradient: standard 0, TorchLean −2.9337e−8 (relative error 0.0096); exact −2.906e−8.

tf32, up to and including the first LayerNorm: the largest relative error is 0.0012, at normalized. No value is a wrong 0.

tf32, up to and including the attention: the largest relative error is 0.033, at weights · v. No value is a wrong 0.

tf32, up to and including the first residual: the largest relative error is 0.033, at weights · v. No value is a wrong 0.

tf32, up to and including the second LayerNorm: the largest relative error is 0.033, at weights · v. No value is a wrong 0.

tf32, up to and including the MLP: the largest relative error is 0.033, at weights · v. No value is a wrong 0.

tf32, up to and including the second residual: the largest relative error is 0.033, at weights · v. No value is a wrong 0.

tf32, up to and including the final LayerNorm and the logits: the largest relative error is 0.033, at weights · v. No value is a wrong 0.

tf32, up to and including both cross-entropy heads: the largest relative error is 0.033, at weights · v. 4 values are 0 where the exact value rounded to tf32 is not (log sum, log p₂, loss, gradient). Target gradient: standard 0, TorchLean −2.9424e−8 (relative error 0.013); exact −2.906e−8.

binary16, up to and including the first LayerNorm: the largest relative error is 0.0012, at normalized. No value is a wrong 0.

binary16, up to and including the attention: the largest relative error is 0.033, at weights · v. No value is a wrong 0.

binary16, up to and including the first residual: the largest relative error is 0.033, at weights · v. No value is a wrong 0.

binary16, up to and including the second LayerNorm: the largest relative error is 0.033, at weights · v. No value is a wrong 0.

binary16, up to and including the MLP: the largest relative error is 0.033, at weights · v. No value is a wrong 0.

binary16, up to and including the second residual: the largest relative error is 0.033, at weights · v. No value is a wrong 0.

binary16, up to and including the final LayerNorm and the logits: the largest relative error is 0.033, at weights · v. No value is a wrong 0.

binary16, up to and including both cross-entropy heads: the largest relative error is 0.033, at weights · v. No value is a wrong 0. 25 values are 0 because the exact value rounds to 0 in binary16. Target gradient: standard 0, TorchLean 0; exact −2.906e−8.

bfloat16, up to and including the first LayerNorm: the largest relative error is 0.0057, at 1/√(var + ε). No value is a wrong 0.

bfloat16, up to and including the attention: the largest relative error is 0.02, at k. No value is a wrong 0.

bfloat16, up to and including the first residual: the largest relative error is 0.02, at k. No value is a wrong 0.

bfloat16, up to and including the second LayerNorm: the largest relative error is 0.04, at x − mean. No value is a wrong 0.

bfloat16, up to and including the MLP: the largest relative error is 0.17, at 1 + tanh z. No value is a wrong 0.

bfloat16, up to and including the second residual: the largest relative error is 0.17, at 1 + tanh z. No value is a wrong 0.

bfloat16, up to and including the final LayerNorm and the logits: the largest relative error is 0.17, at 1 + tanh z. No value is a wrong 0.

bfloat16, up to and including both cross-entropy heads: the largest relative error is 0.17, at 1 + tanh z. 4 values are 0 where the exact value rounded to bfloat16 is not (log sum, log p₂, loss, gradient). Target gradient: standard 0, TorchLean −2.6543e−8 (relative error 0.087); exact −2.906e−8.

posit8, up to and including the first LayerNorm: the largest relative error is 0.096, at normalized. No value is a wrong 0.

posit8, up to and including the attention: the largest relative error is 1.6, at v. No value is a wrong 0.

posit8, up to and including the first residual: the largest relative error is 1.6, at v. No value is a wrong 0.

posit8, up to and including the second LayerNorm: the largest relative error is 1.6, at v. No value is a wrong 0.

posit8, up to and including the MLP: the largest relative error is 2.6, at 1 + tanh z. 7 values are 0 where the exact value rounded to posit8 is not (1 + tanh z, GELU, GELU W₂ + b₂).

posit8, up to and including the second residual: the largest relative error is 2.6, at 1 + tanh z. 7 values are 0 where the exact value rounded to posit8 is not (1 + tanh z, GELU, GELU W₂ + b₂).

posit8, up to and including the final LayerNorm and the logits: the largest relative error is 2.6, at 1 + tanh z. 7 values are 0 where the exact value rounded to posit8 is not (1 + tanh z, GELU, GELU W₂ + b₂).

posit8, up to and including both cross-entropy heads: the largest relative error is 95, at gradient. 11 values are 0 where the exact value rounded to posit8 is not (1 + tanh z, GELU, GELU W₂ + b₂, log sum, log p₂, loss, gradient). Target gradient: standard 0, TorchLean −5.9605e−8 (relative error 1.1); exact −2.906e−8.

E4M3, up to and including the first LayerNorm: the largest relative error is 0.096, at normalized. No value is a wrong 0. In this format exp and log are FloatLib's approximations, not the exact value rounded once.

E4M3, up to and including the attention: the largest relative error is 1.6, at v. No value is a wrong 0. In this format exp and log are FloatLib's approximations, not the exact value rounded once.

E4M3, up to and including the first residual: the largest relative error is 1.6, at v. No value is a wrong 0. In this format exp and log are FloatLib's approximations, not the exact value rounded once.

E4M3, up to and including the second LayerNorm: the largest relative error is 1.6, at v. No value is a wrong 0. In this format exp and log are FloatLib's approximations, not the exact value rounded once.

E4M3, up to and including the MLP: the largest relative error is 2.6, at 1 + tanh z. 7 values are 0 where the exact value rounded to E4M3 is not (1 + tanh z, GELU, GELU W₂ + b₂). In this format exp and log are FloatLib's approximations, not the exact value rounded once.

E4M3, up to and including the second residual: the largest relative error is 2.6, at 1 + tanh z. 7 values are 0 where the exact value rounded to E4M3 is not (1 + tanh z, GELU, GELU W₂ + b₂). In this format exp and log are FloatLib's approximations, not the exact value rounded once.

E4M3, up to and including the final LayerNorm and the logits: the largest relative error is 2.6, at 1 + tanh z. 7 values are 0 where the exact value rounded to E4M3 is not (1 + tanh z, GELU, GELU W₂ + b₂). In this format exp and log are FloatLib's approximations, not the exact value rounded once.

E4M3, up to and including both cross-entropy heads: the largest relative error is 2.6, at 1 + tanh z. 7 values are 0 where the exact value rounded to E4M3 is not (1 + tanh z, GELU, GELU W₂ + b₂). 25 values are 0 because the exact value rounds to 0 in E4M3. Target gradient: standard 0, TorchLean 0; exact −2.906e−8. In this format exp and log are FloatLib's approximations, not the exact value rounded once.

E4M3 FNUZ, up to and including the first LayerNorm: the largest relative error is 0.096, at normalized. No value is a wrong 0. In this format exp and log are FloatLib's approximations, not the exact value rounded once.

E4M3 FNUZ, up to and including the attention: the largest relative error is 1.6, at v. No value is a wrong 0. In this format exp and log are FloatLib's approximations, not the exact value rounded once.

E4M3 FNUZ, up to and including the first residual: the largest relative error is 1.6, at v. No value is a wrong 0. In this format exp and log are FloatLib's approximations, not the exact value rounded once.

E4M3 FNUZ, up to and including the second LayerNorm: the largest relative error is 1.6, at v. No value is a wrong 0. In this format exp and log are FloatLib's approximations, not the exact value rounded once.

E4M3 FNUZ, up to and including the MLP: the largest relative error is 2.6, at 1 + tanh z. 7 values are 0 where the exact value rounded to E4M3 FNUZ is not (1 + tanh z, GELU, GELU W₂ + b₂). In this format exp and log are FloatLib's approximations, not the exact value rounded once.

E4M3 FNUZ, up to and including the second residual: the largest relative error is 2.6, at 1 + tanh z. 7 values are 0 where the exact value rounded to E4M3 FNUZ is not (1 + tanh z, GELU, GELU W₂ + b₂). In this format exp and log are FloatLib's approximations, not the exact value rounded once.

E4M3 FNUZ, up to and including the final LayerNorm and the logits: the largest relative error is 2.6, at 1 + tanh z. 7 values are 0 where the exact value rounded to E4M3 FNUZ is not (1 + tanh z, GELU, GELU W₂ + b₂). In this format exp and log are FloatLib's approximations, not the exact value rounded once.

E4M3 FNUZ, up to and including both cross-entropy heads: the largest relative error is 2.6, at 1 + tanh z. 7 values are 0 where the exact value rounded to E4M3 FNUZ is not (1 + tanh z, GELU, GELU W₂ + b₂). 25 values are 0 because the exact value rounds to 0 in E4M3 FNUZ. Target gradient: standard 0, TorchLean 0; exact −2.906e−8. In this format exp and log are FloatLib's approximations, not the exact value rounded once.

E5M2, up to and including the first LayerNorm: the largest relative error is 0.25, at normalized. 3 values are 0 where the exact value rounded to E5M2 is not (mean, x − mean, normalized).

E5M2, up to and including the attention: the largest relative error is 6.6, at weights · v. 4 values are 0 where the exact value rounded to E5M2 is not (mean, x − mean, normalized, v).

E5M2, up to and including the first residual: the largest relative error is 6.6, at weights · v. 4 values are 0 where the exact value rounded to E5M2 is not (mean, x − mean, normalized, v).

E5M2, up to and including the second LayerNorm: the largest relative error is 6.6, at weights · v. 5 values are 0 where the exact value rounded to E5M2 is not (mean, x − mean, normalized, v).

E5M2, up to and including the MLP: the largest relative error is 6.6, at weights · v. 17 values are 0 where the exact value rounded to E5M2 is not (mean, x − mean, normalized, v, 1 + tanh z, GELU).

E5M2, up to and including the second residual: the largest relative error is 6.6, at weights · v. 18 values are 0 where the exact value rounded to E5M2 is not (mean, x − mean, normalized, v, 1 + tanh z, GELU, x + MLP).

E5M2, up to and including the final LayerNorm and the logits: the largest relative error is 6.6, at weights · v. 20 values are 0 where the exact value rounded to E5M2 is not (mean, x − mean, normalized, v, 1 + tanh z, GELU, x + MLP, logits).

E5M2, up to and including both cross-entropy heads: the largest relative error is 6.6, at weights · v. 20 values are 0 where the exact value rounded to E5M2 is not (mean, x − mean, normalized, v, 1 + tanh z, GELU, x + MLP, logits). 25 values are 0 because the exact value rounds to 0 in E5M2. Target gradient: standard 0, TorchLean 0; exact −2.906e−8.

E5M2 FNUZ, up to and including the first LayerNorm: the largest relative error is 0.25, at normalized. 3 values are 0 where the exact value rounded to E5M2 FNUZ is not (mean, x − mean, normalized). In this format exp and log are FloatLib's approximations, not the exact value rounded once.

E5M2 FNUZ, up to and including the attention: the largest relative error is 6.6, at weights · v. 4 values are 0 where the exact value rounded to E5M2 FNUZ is not (mean, x − mean, normalized, v). In this format exp and log are FloatLib's approximations, not the exact value rounded once.

E5M2 FNUZ, up to and including the first residual: the largest relative error is 6.6, at weights · v. 4 values are 0 where the exact value rounded to E5M2 FNUZ is not (mean, x − mean, normalized, v). In this format exp and log are FloatLib's approximations, not the exact value rounded once.

E5M2 FNUZ, up to and including the second LayerNorm: the largest relative error is 6.6, at weights · v. 5 values are 0 where the exact value rounded to E5M2 FNUZ is not (mean, x − mean, normalized, v). In this format exp and log are FloatLib's approximations, not the exact value rounded once.

E5M2 FNUZ, up to and including the MLP: the largest relative error is 6.6, at weights · v. 17 values are 0 where the exact value rounded to E5M2 FNUZ is not (mean, x − mean, normalized, v, 1 + tanh z, GELU). In this format exp and log are FloatLib's approximations, not the exact value rounded once.

E5M2 FNUZ, up to and including the second residual: the largest relative error is 6.6, at weights · v. 18 values are 0 where the exact value rounded to E5M2 FNUZ is not (mean, x − mean, normalized, v, 1 + tanh z, GELU, x + MLP). In this format exp and log are FloatLib's approximations, not the exact value rounded once.

E5M2 FNUZ, up to and including the final LayerNorm and the logits: the largest relative error is 6.6, at weights · v. 20 values are 0 where the exact value rounded to E5M2 FNUZ is not (mean, x − mean, normalized, v, 1 + tanh z, GELU, x + MLP, logits). In this format exp and log are FloatLib's approximations, not the exact value rounded once.

E5M2 FNUZ, up to and including both cross-entropy heads: the largest relative error is 350, at gradient. 20 values are 0 where the exact value rounded to E5M2 FNUZ is not (mean, x − mean, normalized, v, 1 + tanh z, GELU, x + MLP, logits). 16 values are 0 because the exact value rounds to 0 in E5M2 FNUZ. Target gradient: standard 0, TorchLean −7.6294e−6 (relative error 260); exact −2.906e−8. In this format exp and log are FloatLib's approximations, not the exact value rounded once.

LayerNorm, attention, residual

meanx − meanvariance1/√(var + ε)normalizedqkvscoresrow maxexprow sumweightsweights · vprojectionx + attention

LayerNorm, MLP with tanh-GELU, residual

meanx − meanvariance1/√(var + ε)normalizedx W₁ + b₁ztanh z1 + tanh zGELUGELU W₂ + b₂x + MLP

final LayerNorm and logits, last token

meanx − meanvariance1/√(var + ε)normalizedlogits

standard cross-entropy: softmax, log of the sum, p − 1

maxshiftexpsumlog sumlog p₂lossgradient

TorchLean's cross-entropy: pivot, log1p of the tail, expm1

shiftexp, otherstaillog1p(tail)log plossgradient

LayerNorm, attention, residual

meanx − meanvariance1/√(var + ε)normalizedqkvscoresrow maxexprow sumweightsweights · vprojectionx + attention

LayerNorm, MLP with tanh-GELU, residual

meanx − meanvariance1/√(var + ε)normalizedx W₁ + b₁ztanh z1 + tanh zGELUGELU W₂ + b₂x + MLP

final LayerNorm and logits, last token

meanx − meanvariance1/√(var + ε)normalizedlogits

standard cross-entropy: softmax, log of the sum, p − 1

maxshiftexpsumlog sumlog p₂lossgradient

TorchLean's cross-entropy: pivot, log1p of the tail, expm1

shiftexp, otherstaillog1p(tail)log plossgradient

LayerNorm, attention, residual

meanx − meanvariance1/√(var + ε)normalizedqkvscoresrow maxexprow sumweightsweights · vprojectionx + attention

LayerNorm, MLP with tanh-GELU, residual

meanx − meanvariance1/√(var + ε)normalizedx W₁ + b₁ztanh z1 + tanh zGELUGELU W₂ + b₂x + MLP

final LayerNorm and logits, last token

meanx − meanvariance1/√(var + ε)normalizedlogits

standard cross-entropy: softmax, log of the sum, p − 1

maxshiftexpsumlog sumlog p₂lossgradient

TorchLean's cross-entropy: pivot, log1p of the tail, expm1

shiftexp, otherstaillog1p(tail)log plossgradient

LayerNorm, attention, residual

meanx − meanvariance1/√(var + ε)normalizedqkvscoresrow maxexprow sumweightsweights · vprojectionx + attention

LayerNorm, MLP with tanh-GELU, residual

meanx − meanvariance1/√(var + ε)normalizedx W₁ + b₁ztanh z1 + tanh zGELUGELU W₂ + b₂x + MLP

final LayerNorm and logits, last token

meanx − meanvariance1/√(var + ε)normalizedlogits

standard cross-entropy: softmax, log of the sum, p − 1

maxshiftexpsumlog sumlog p₂lossgradient

TorchLean's cross-entropy: pivot, log1p of the tail, expm1

shiftexp, otherstaillog1p(tail)log plossgradient

LayerNorm, attention, residual

meanx − meanvariance1/√(var + ε)normalizedqkvscoresrow maxexprow sumweightsweights · vprojectionx + attention

LayerNorm, MLP with tanh-GELU, residual

meanx − meanvariance1/√(var + ε)normalizedx W₁ + b₁ztanh z1 + tanh zGELUGELU W₂ + b₂x + MLP

final LayerNorm and logits, last token

meanx − meanvariance1/√(var + ε)normalizedlogits

standard cross-entropy: softmax, log of the sum, p − 1

maxshiftexpsumlog sumlog p₂lossgradient

TorchLean's cross-entropy: pivot, log1p of the tail, expm1

shiftexp, otherstaillog1p(tail)log plossgradient

LayerNorm, attention, residual

meanx − meanvariance1/√(var + ε)normalizedqkvscoresrow maxexprow sumweightsweights · vprojectionx + attention

LayerNorm, MLP with tanh-GELU, residual

meanx − meanvariance1/√(var + ε)normalizedx W₁ + b₁ztanh z1 + tanh zGELUGELU W₂ + b₂x + MLP

final LayerNorm and logits, last token

meanx − meanvariance1/√(var + ε)normalizedlogits

standard cross-entropy: softmax, log of the sum, p − 1

maxshiftexpsumlog sumlog p₂lossgradient

TorchLean's cross-entropy: pivot, log1p of the tail, expm1

shiftexp, otherstaillog1p(tail)log plossgradient

LayerNorm, attention, residual

meanx − meanvariance1/√(var + ε)normalizedqkvscoresrow maxexprow sumweightsweights · vprojectionx + attention

LayerNorm, MLP with tanh-GELU, residual

meanx − meanvariance1/√(var + ε)normalizedx W₁ + b₁ztanh z1 + tanh zGELUGELU W₂ + b₂x + MLP

final LayerNorm and logits, last token

meanx − meanvariance1/√(var + ε)normalizedlogits

standard cross-entropy: softmax, log of the sum, p − 1

maxshiftexpsumlog sumlog p₂lossgradient

TorchLean's cross-entropy: pivot, log1p of the tail, expm1

shiftexp, otherstaillog1p(tail)log plossgradient

LayerNorm, attention, residual

meanx − meanvariance1/√(var + ε)normalizedqkvscoresrow maxexprow sumweightsweights · vprojectionx + attention

LayerNorm, MLP with tanh-GELU, residual

meanx − meanvariance1/√(var + ε)normalizedx W₁ + b₁ztanh z1 + tanh zGELUGELU W₂ + b₂x + MLP

final LayerNorm and logits, last token

meanx − meanvariance1/√(var + ε)normalizedlogits

standard cross-entropy: softmax, log of the sum, p − 1

maxshiftexpsumlog sumlog p₂lossgradient

TorchLean's cross-entropy: pivot, log1p of the tail, expm1

shiftexp, otherstaillog1p(tail)log plossgradient

LayerNorm, attention, residual

meanx − meanvariance1/√(var + ε)normalizedqkvscoresrow maxexprow sumweightsweights · vprojectionx + attention

LayerNorm, MLP with tanh-GELU, residual

meanx − meanvariance1/√(var + ε)normalizedx W₁ + b₁ztanh z1 + tanh zGELUGELU W₂ + b₂x + MLP

final LayerNorm and logits, last token

meanx − meanvariance1/√(var + ε)normalizedlogits

standard cross-entropy: softmax, log of the sum, p − 1

maxshiftexpsumlog sumlog p₂lossgradient

TorchLean's cross-entropy: pivot, log1p of the tail, expm1

shiftexp, otherstaillog1p(tail)log plossgradient

LayerNorm, attention, residual

meanx − meanvariance1/√(var + ε)normalizedqkvscoresrow maxexprow sumweightsweights · vprojectionx + attention

LayerNorm, MLP with tanh-GELU, residual

meanx − meanvariance1/√(var + ε)normalizedx W₁ + b₁ztanh z1 + tanh zGELUGELU W₂ + b₂x + MLP

final LayerNorm and logits, last token

meanx − meanvariance1/√(var + ε)normalizedlogits

standard cross-entropy: softmax, log of the sum, p − 1

maxshiftexpsumlog sumlog p₂lossgradient

TorchLean's cross-entropy: pivot, log1p of the tail, expm1

shiftexp, otherstaillog1p(tail)log plossgradient

LayerNorm, attention, residual

meanx − meanvariance1/√(var + ε)normalizedqkvscoresrow maxexprow sumweightsweights · vprojectionx + attention

LayerNorm, MLP with tanh-GELU, residual

meanx − meanvariance1/√(var + ε)normalizedx W₁ + b₁ztanh z1 + tanh zGELUGELU W₂ + b₂x + MLP

final LayerNorm and logits, last token

meanx − meanvariance1/√(var + ε)normalizedlogits

standard cross-entropy: softmax, log of the sum, p − 1

maxshiftexpsumlog sumlog p₂lossgradient

TorchLean's cross-entropy: pivot, log1p of the tail, expm1

shiftexp, otherstaillog1p(tail)log plossgradient

LayerNorm, attention, residual

meanx − meanvariance1/√(var + ε)normalizedqkvscoresrow maxexprow sumweightsweights · vprojectionx + attention

LayerNorm, MLP with tanh-GELU, residual

meanx − meanvariance1/√(var + ε)normalizedx W₁ + b₁ztanh z1 + tanh zGELUGELU W₂ + b₂x + MLP

final LayerNorm and logits, last token

meanx − meanvariance1/√(var + ε)normalizedlogits

standard cross-entropy: softmax, log of the sum, p − 1

maxshiftexpsumlog sumlog p₂lossgradient

TorchLean's cross-entropy: pivot, log1p of the tail, expm1

shiftexp, otherstaillog1p(tail)log plossgradient
Table: every format, worst relative error by stage
formatLayerNorm and attentionMLPlogitsstandard headTorchLean headstandard gradientTorchLean gradient
binary644.8e−153e−151.5e−151.2e−93.5e−15−2.9058e−8−2.9058e−8
posit321.7e−71.2e−73e−70.0262.6e−7−2.9802e−8−2.9058e−8
binary321.7e−64e−69.2e−72.8e−6; 4 wrong 0s2.8e−60−2.9058e−8
posit160.00980.00470.00850.014; 4 wrong 0s0.0140−2.9337e−8
tf320.0330.0150.00810.016; 4 wrong 0s0.0160−2.9424e−8
binary160.0330.0150.00818.6e−48.6e−400
bfloat160.020.170.0170.1; 4 wrong 0s0.10−2.6543e−8
posit81.62.6; 7 wrong 0s0.795; 4 wrong 0s950−5.9605e−8
E4M31.62.6; 7 wrong 0s0.70.0940.09400
E4M3 FNUZ1.62.6; 7 wrong 0s0.70.0940.09400
E5M26.6; 4 wrong 0s0.78; 14 wrong 0s0.24; 2 wrong 0s0.320.3200
E5M2 FNUZ6.6; 4 wrong 0s0.78; 14 wrong 0s0.24; 2 wrong 0s3503500−7.6294e−6
Figure 6. Following roundoff through a transformer block.Each square is one recorded scalar in the selected stage of a small transformer block. Color shows relative error against the real-valued calculation. The loss stage compares standard and replacement cross-entropy. Black marks a computed zero with a nonzero real-valued reference; gray marks a correctly rounded zero.
Arithmetic and reference values

The pre-LayerNorm block has three tokens of width 4, causal attention, an MLP of width 8 with tanh-GELU, and five output classes with target class 2. Inputs and weights have at most two significant bits and magnitudes between 1/8 and 8, so every tested format represents them exactly. Error comes from arithmetic and rounding the GELU constants and LayerNorm epsilon, 2^-16. In binary formats, tanh uses FloatLib's approximation without an accuracy theorem; this also applies to exp and log in E4M3 and the FNUZ formats. Binary runs use TorchLean's Context. The posit program was checked bit for bit against that Context in six binary formats. References use mpmath at 256 bits.

In float32, TF32, bfloat16, and posit16, four values incorrectly became zero in the loss calculation: the log of the sum, the target log probability, the loss, and the target gradient. The earlier computations had rounding error but no incorrect zeros, NaNs, or infinities. Binary16 is different: zero was the correctly rounded loss because the true value was too small for that format. Several formats with 8 bits lost information earlier, especially around GELU. And repairing the loss does not undo errors from the rest of the block. In float32, the rewritten target gradient still differed from the real valued block by about \(1.5\times10^{-6}\) relatively, after rounding near 21 moved one logit by about \(9.5\times10^{-7}\). The trace let us follow that error back to the rounded logit.

Rewriting formulas, proving guarantees

The softmax fix made me want to try the same approach on the other failures. We tested alternative formulas that compute the same function over the reals but avoid cancellation or intermediate overflow in floating point. The table below shows the original formulas, the replacements we tried, and what we have proved about them in Lean.

Here, \(\sigma\) means sigmoid, \(\operatorname{fl}\) means rounding, and \(\mathrm{CDF}(x)\) is a cumulative distribution function. A once-rounded reference computes the exact result and rounds only at the end.

OperationBefore / afterLean proof
Cross-entropy target gradient
Before\(p_t-1\)
After
\(\begin{aligned}T&=\sum_{j\ne t}e^{z_j-z_t}\\L&=\operatorname{log1p}(T)\\g_t&=\operatorname{expm1}(-L)\end{aligned}\)The target has the largest logit. The underflow fallback is discussed below.
Tail rewrite: bound proved. Underflow fallback: bound pending.
GRPO KL penalty
Before\(e^d-d-1\)
After
\(\operatorname{expm1}(d)-d\)
Rewrite bound proved on a restricted domain.
tanh-GELU
Before\(\tfrac12 x(1+\tanh z)\)
After
\(x\,\sigma(2z)\)
Measured; bound pending.
Sigmoid
BeforeLibrary kernel
After
\(\begin{cases}\dfrac{e^x}{1+e^x},&x<0,\\[5pt]\dfrac{1}{1+e^{-x}},&x\ge0.\end{cases}\)
Once-rounded reference proved.
Soft-margin loss and gradient
Before\(\log(1+e^{-yx})\)
After
\(\begin{aligned}m&=\max(0,-yx)\\L&=m+\operatorname{log1p}(e^{-|yx|})\\g&=-y\,\sigma(-yx)\end{aligned}\)
Once-rounded gradient proved.
Weibull survival probability
Before\(1-\operatorname{CDF}(x)\)
After
\(e^{-(x/\lambda)^k}\)\(\lambda\) and \(k\) are the scale and shape parameters.
Once-rounded reference proved.
Variance
Before\(\overline{x^2}-\bar x^2\)
After
\(\begin{aligned}c_i&=x_i-\bar x\\v&=\overline{c^2}-\bar c^2\end{aligned}\)Corrected two-pass form.
Once-rounded reference proved.
Diffusion noise level
Before\(\sqrt{1-\bar\alpha}\)
After
\(\begin{aligned}s&=\sum_i\operatorname{log1p}(-\beta_i)\\q&=\sqrt{-\operatorname{expm1}(s)}\end{aligned}\)\(\beta_i\) are the noise rates; \(\bar\alpha=\prod_i(1-\beta_i)\).
Measured; bound pending.
Sums in float16
Before\(\begin{aligned}s_0&=0\\s_{i+1}&=\operatorname{fl}(s_i+x_i)\end{aligned}\)
After
\(\operatorname{fl}\!\left(\sum_i x_i\right)\)An exact sum rounded once, or a wider accumulator.
Planned.
Reciprocal square root and floor division
Before\(\begin{gathered}\operatorname{fl}(1/\operatorname{fl}(\sqrt{x}))\\\lfloor\operatorname{fl}(a/b)\rfloor\end{gathered}\)
After
\(\begin{gathered}\operatorname{fl}(1/\sqrt{x})\\\operatorname{fl}(\lfloor a/b\rfloor)\end{gathered}\)\(x>0\) and \(b\ne0\), respectively.
One-rounding program proved.

The small exponentials in the softmax rewrite can still underflow. TorchLean therefore also has a fallback that combines them through their logarithms and is used only when every output is finite. For our worked input, float32 keeps the same answer, while binary16 recovers the correctly rounded gradient \(-2^{-24}\). We proved that the fallback preserves finiteness whenever the original computation is finite, for every supported scalar type and class count. A comparably tight general error bound for this fallback is still pending.

What I hope comes next

I want to keep pushing this with TorchLean and FloatLib, from individual operators to training code and kernels. That means getting tighter bounds and checking how well the modeled arithmetic matches the hardware. I'd also like to understand which local errors actually change a full training run.

I think the future here is bright : ) Verification can help us find numerical bugs at scale, test alternative formulas, and prove useful guarantees about the fixes. I'd love to see these checks become part of everyday ML development, so that changing a kernel or a number format comes with a check of its numerical behavior.

I'd be very happy to work with more experts in numerical analysis and floating-point arithmetic on better formulas and tighter bounds. If this is your area, I'd love to compare notes and work on these problems together.