checked design
This page explains which operations on dual numbers have checked forms, how
their errors arise from the derivative rules, and why the facade reuses the
arithmetic error model.
Design goal
Let differentiated code report invalid operations as values, with the same error type that scalar Luna Flow code uses, and make it impossible for a checked operation to return a valid value with an invalid derivative.
Mathematical background
Where a derivative fails
A checked operation must fail when either component of is undefined. For the two checked operations:
The quotient fails exactly where the value fails, because in exact arithmetic. The square root is different: exists at , but is not differentiable there (its difference quotient is unbounded), so the domain of the dual operation is the open half-line , smaller than the domain of the scalar square root.
Floating-point domains
In Double, can be zero for non-zero : underflows to
for (rounding to nearest, with gradual underflow) even
though may be finite. The checked quotient then reports a division by
zero from the tangent. Such inputs are better rescaled; the
dual design assumes no underflow.
Design decisions
Check both components
Problem. A checked scalar operation can succeed while the derivative does not exist.
Choice. Each checked dual operation calls the checked scalar operation
for the value and div_checked for the tangent division, and returns the
first error. This makes the dual domain the intersection of the domains of
and , as derived above; in particular sqrt_checked fails at .
No special case for a zero tangent
At with the tangent is the indeterminate . One could
return (a constant input has no derivative to report), but that would
make the result depend on how a constant was produced. The implementation
lets T decide, and for Double this is a domain error.
Reuse arithmetic
Dual[T] implements DivChecked and SqrtChecked from arithmetic, and
this facade re-exports exactly those traits with ArithmeticContext,
ArithmeticError, ArithmeticErrorKind and RoundingMode. Generic checked
code therefore runs on Double and on Dual[Double] without adaptation,
and errors from both levels have one type.
Only division and square root
arithmetic defines checked traits for division, square root, comparison,
parsing and integer powers. Of these, only division and square root are
operations on with a derivative rule in this repository, so
only they have checked dual forms. Logarithms and trigonometric functions
follow the unchecked semantics of T.
Correctness and invariants
div_checked(x, y)succeeds exactly whenT’sdiv_checkedsucceeds for both and ; then it equalsx / ycomputed with the same operations.sqrt_checked(x)succeeds exactly whenT’ssqrt_checked(a)anddiv_checked(b, 2√a)succeed; forDoublethat is , or NaN.- The context is passed to
Tunchanged and never modified.
Alternatives rejected
- A dedicated autodiff error type. It would duplicate
ArithmeticErrorand force conversions at every boundary. Optionresults. They lose the reason for the failure.- Checking only the value. It would return infinite or NaN derivatives from a “checked” operation.
Boundaries
- No checked logarithm, exponential or trigonometric operations.
- No contextual (
ArithmeticOutcome) operations and no rounding diagnostics. - No automatic rescaling of tiny divisors.