bin_float design
bin_float implements IEEE 754 binary floating-point arithmetic at any
precision. This page explains the mathematics behind it: the value set, the
rounding functions and the error model they satisfy, how each operation
decides the correctly rounded result from exact integer data, how the
exponent range, tininess and the status flags are handled, why the IEEE
remainder is exact, how decimal conversion and the elementary functions are
certified, and why the fast integer kernels cannot change a result. The
API reference lists the callable surface and the
tutorial shows it in use.
Design goal
Every operation of bin_float returns the value that IEEE 754-2019 requires
of a correctly rounded operation, for the exact real
, together with exactly the IEEE status flags, for every precision
from 1 to bits and every exponent range up to . The
same code serves two audiences: arbitrary-precision numerics that need
dyadic values far beyond Double, and bit-exact emulation of binary16,
binary32, binary64 and binary128 including subnormals, the five rounding
directions and both tininess rules. There is no hidden state: precision,
rounding and range travel in an immutable BinaryContext, and flags travel
back as a value.
Mathematical background
Dyadic values and the stored triple
A finite BinFloat denotes the dyadic rational
where is a BinCoeff and is exponent2(). The representation is
canonical: if then is odd, and if then . Every
dyadic rational has exactly one such form (factor out
), so two finite values are numerically equal exactly when
their signs (for nonzero values), coefficients and exponents agree. The
exponent of the leading bit is
and every comparison, range check and rounding decision below is phrased in terms of and instead of floating logarithms. Each value also carries a precision with ; it records the format the value belongs to and is the default precision of plain operations on it.
The IEEE 754 binary formats
A binary interchange format with bits has a sign bit, a -bit biased exponent field and a -bit trailing significand field (IEEE 754-2019 clause 3.4).11 IEEE Std 754-2019, IEEE Standard for Floating-Point Arithmetic: clause 3 (formats), 4.3 (rounding-direction attributes), 5 (operations), 6 (infinities, NaNs, signed zero), 7 (default exception handling). With , the bias and , an encoding means
| Format | largest | smallest normal | smallest subnormal | |||||
|---|---|---|---|---|---|---|---|---|
| binary16 | 16 | 5 | 11 | 15 | −14 | |||
| binary32 | 32 | 8 | 24 | 127 | −126 | |||
| binary64 | 64 | 11 | 53 | 1023 | −1022 | |||
| binary128 | 128 | 15 | 113 | 16383 | −16382 |
Forgetting the encoding, the finite values of the format are
A BinaryContext is exactly this triple plus a rounding direction and a
tininess rule. Its and are leading-bit exponents, so a
normal number has , and the
grid below has the fixed quantum
the smallest positive subnormal. Missing bounds are replaced by the
implementation range , which is large enough that every
exponent arithmetic step fits a 64-bit intermediate and every stored exponent
an Int; binary_precision_max keeps in range
too.
Rounding functions
For let and
, extending by beyond
for the moment. The six rounding directions of
BinaryRoundingMode are the maps
where RA (RoundAwayFromZero) is not an IEEE attribute but the GDA
“round-up” mode that @lf_arith.RoundingMode shares with the decimal cores.
Two properties of every above carry most of the proofs on this page:
(R1) holds because on . (R2) holds because each is one of the two neighbours of chosen by a rule that only moves from to as increases through a cell .
The standard error model
Let be the unit roundoff. Take with and (the normal range). The points of in that binade are spaced apart, so
where RN is RNE or RNA. Writing gives the standard model
The nearest bound sharpens to by dividing by instead of .22 N. J. Higham, Accuracy and Stability of Numerical Algorithms, 2nd ed., SIAM 2002, §2.2; D. Goldberg, “What every computer scientist should know about floating-point arithmetic”, ACM Computing Surveys 23(1), 1991. Below the spacing is the constant , so the error is absolute: and . Both regimes together give the model with an underflow term,
for nearest rounding ( and for directed rounding). Addition and subtraction never need : if then both are integer multiples of , so is , and a multiple of below lies in . Hence a subnormal sum is exact, which is why gradual underflow keeps .33 J.-M. Muller et al., Handbook of Floating-Point Arithmetic, 2nd ed., Birkhäuser 2018, §2.1 and §4.3.
Correct rounding is a stronger property than the model: the result is the
one point , not merely some point within . All of
bin_float is built to return that point, so the model above holds for every
operation, including the elementary functions.
Design decisions
Round once from exact data
Problem. A result must equal for the exact real , but may need far more bits than (a product of two -bit numbers has ), or infinitely many (a quotient, a square root, ).
Options. Compute in a wider format and round again, as hardware without FMA does; or keep a fixed number of guard bits; or decide the rounding from exact information.
Choice. Every operation computes an exact description of and calls
one finalizer. For dyadic results (sum, difference, product, fma,
scaleb, remainder, conversion) the description is the exact integer
magnitude and exponent with . The finalizer picks the
shift
the larger of the precision shift and the shift onto the subnormal grid, and splits with and into three items of data:
These are the classical round and sticky bits, read from the coefficient by
test_bit and ctz without building any shifted copy. They determine
every rounding direction: with the last bit of ,
| Direction | increment when |
|---|---|
| RNE | |
| RNA | |
| RZ | never |
| RU | |
| RD | |
| RA |
Derivation. , , and . RNE rounds the magnitude up when , or when and is odd; that is . The directed rows round the magnitude up exactly when and the direction points away from zero for the sign . Inexactness is .
Why. Because already includes the subnormal shift, a tiny result is rounded once, directly from , to the grid . Rounding first to bits and then to the subnormal grid would be a double rounding: a value just above a midpoint of the coarse grid can be pushed onto that midpoint by the first rounding and then rounded the wrong way by the second. A carry out of (when ) only raises by one; the result is re-normalized and the overflow test below is applied to the rounded value.
Division from quotient and remainder
Problem. with , is a rational (, , ) whose binary expansion is usually infinite.
Choice. First the exact leading exponent: with , is if and otherwise, one integer comparison. That fixes the target exponent , and then one integer division
gives directly, and the remainder gives the rounding data: , so
No approximation of is involved; the rounding is decided by the sign of . When the shift is moved to the denominator, and a quotient below one unit is decided by comparing with without forming it.
Square root from an integer root and a midpoint test
Problem. is irrational unless is a square.
Choice. The leading exponent is (floor division), which fixes as above. Write the radicand as , so . An exact integer square root gives with remainder ; the root is exact iff the remainder is zero. Otherwise the rounding data come from the midpoint :
an exact comparison of integers (with the power of two moved to the other side when is fractional). So and . When is an integer the right side is odd and the left even, so the root is never exactly a midpoint; this is the classical fact that of a -bit number is never a -bit midpoint.44 Muller et al., Handbook of Floating-Point Arithmetic, §5.3 and §7.6. The equality branch is still kept, because an operand with more bits than the context precision can make an exact midpoint (for example rounded to one bit).
Exponent range, overflow and underflow
Overflow is decided on the rounded value: if the rounded result has , the operation overflows, which is IEEE 754’s “after rounding” rule (clause 7.4). From the rounding table this happens at the thresholds
because a value in rounds to
nearest down to , while the tie
goes to the even neighbour , which lies outside . An
overflowing result is for the first two groups and for
the third, always with overflow and inexact. In binary16,
and :
///|
test "binary16 overflow threshold under nearest rounding" {
let ctx = @bin_float.BinaryContext::binary16()
let (below, below_flags) = @bin_float.BinFloat::from_int(65519).round_ctx(ctx)
let (at, at_flags) = @bin_float.BinFloat::from_int(65520).round_ctx(ctx)
inspect("\{below} \{below_flags.overflow()}", content="2047p5 false")
inspect("\{at} \{at_flags.overflow()}", content="inf true")
}
Tininess. A nonzero result is tiny when it lies strictly between
. IEEE 754-2019 (clause 7.5) allows two readings, and
TininessDetection selects one:
where rounds to bits with an unbounded exponent range. The finalizer computes exactly and, for the after-rounding rule, a second split of the same magnitude at the precision shift alone. The two readings differ only for just below that rounds up to it at bits: for binary16, is tiny before rounding but rounds at 11 bits to , which is not tiny.
Underflow flag. Under default exception handling the underflow flag is
raised for a tiny result only when it is also inexact. The finalizer returns
no flags at all for an exact result, so an exact subnormal (for example any
subnormal difference, as shown above) raises nothing. The binary16 product
shows the full rule: the exact value
is tiny under both readings, lies halfway between two
subnormals of spacing , rounds to the even neighbour , the
smallest normal, and raises underflow and inexact, although the encoded
result 0x0400 is normal.
///|
test "underflow is raised for a tiny inexact result that rounds to normal" {
let format = @bin_float.BinaryInterchangeFormat::Binary16
let smallest_normal = @bin_float.BinaryInterchange::from_hex("0400", format)
.unwrap()
.to_bin_float()
let below_one = @bin_float.BinaryInterchange::from_hex("3BFF", format)
.unwrap()
.to_bin_float()
let (product, flags) = smallest_normal.mul_ctx(below_one, format.context())
inspect(product.to_interchange(format).0.to_hex(), content="0400")
inspect("\{flags.underflow()} \{flags.inexact()}", content="true true")
}
Far below the range. A result certainly smaller than in
magnitude (decided from exponent bounds without forming it, for example
) rounds to or according to the
direction, with underflow and inexact. A result certainly above the range
goes to the overflow result.
Signed zeros and NaNs
An exact zero sum with of opposite sign is in every
direction except RD, where it is ; (clause 6.3).
Products and quotients take the exclusive-or of the signs. A NaN operand
yields the first NaN operand, quieted, with its sign and payload
(clause 6.2.3 allows any input NaN), and invalid_operation is raised exactly
when an operand is a signaling NaN or the operation is invalid on its own
(, , , ,
, ,
). Flags are values: combine is the
bitwise OR, so the flags of a computation form a commutative idempotent
monoid and can be accumulated in any order, which a global sticky register
cannot offer to concurrent code.
Far-apart operands in addition
Problem. is exact as a dyadic number, but forming it needs a two-billion-bit coefficient.
Choice. When the leading exponents differ by more than , the smaller operand is truncated at position and everything below is replaced by one sticky bit: the integer part of the truncated low operand enters exactly, and if anything was discarded the magnitude becomes (for subtraction ) at half the unit.
Why it is exact for rounding. The result has , so the rounding position is at least and the round bit at least one below it, while every discarded bit lies at or below . The discarded part therefore changes neither nor , only whether is set, and the substitute bit sets exactly when something nonzero was discarded. For subtraction, with , so the same substitution applies to the borrowed form. The complete argument, including the subnormal shift, is in the attachment below.
Fused multiply-add
fma_ctx forms the product exactly as a value whose
precision equals its own bit length, and passes it to the addition finalizer,
so is rounded once (clause 5.4.1). The difference from two
roundings is the point of the operation: for in
binary64, is lost by
mul_ctx followed by sub_ctx (the second operation sees two equal numbers)
but fma_ctx(a, a, -RN(a·a)) returns it exactly, .
That the result is exact is Dekker’s theorem: the error of a rounded product
is itself in when no underflow occurs.55 T. J. Dekker, “A floating-point technique for extending the
available precision”, Numerische Mathematik 18, 1971; Muller et al.,
§4.4. If the product exponent
leaves the Int range, the product either certainly overflows, or it is so
small that it acts as a sticky bit next to a nonzero addend; the code places a
single bit positions below the addend’s last bit, which by the
far-operand argument above rounds identically.
IEEE remainder is exact
Claim. If (same precision , same range) and , then with lies in .
Proof. Write , with and . By the choice of , . If then . Otherwise , so . Now is an integer multiple of .
- If : with , so .
- If : with , so .
In both cases , the exponent is at least , and , so .
The implementation never forms , which can have bits. With , , (integers), it computes by modular exponentiation of when . Writing , , gives , so alone yields both and the parity of , which is all the ties-to-even choice of needs. The exact then goes through the usual finalizer; by the claim, no rounding happens for operands of the context’s format.
Neighbours, scaling and integral values
next_up_ctx(x) adds a positive step to and rounds toward
, where .
Every gap between consecutive points of next to is at least
and itself is a
multiple of , so for , and
by the definition of RU the result is the least point of above . The
same argument works for an with more than bits, which is why such
operands are accepted. The flags of this internal addition are discarded,
because nextUp is quiet (clause 5.3.1) even when it steps from to
.
scaleb_ctx(x, n) is the finalizer applied to : exact in the
normal range, correctly rounded with underflow and overflow outside it.
logb_ctx returns , which is exact and correct for
subnormal because is computed on the integer
coefficient. The integral roundings use the same round and sticky bits with
(the bits below the binary point); to_int_ctx and its
siblings round first and then compare the integer with the target range,
reporting invalid_operation instead of returning an implementation-defined
sentinel.
Decimal conversion
Parsing. from_string_ctx reads exactly ( an integer
without trailing zeros). For up to
( the number of
digits) it is rounded exactly: by the dyadic
finalizer for , and by the division
finalizer for . Beyond that bound it uses directed enclosures
at a working precision , doubled until both ends round to the same value
with the same flags. The bound makes the loop terminate. The rounding
breakpoints of a direction are the points of (directed modes) or the
midpoints between them (nearest modes); both are dyadic with at most
significant bits. For the odd part of is a multiple of
, and beyond the bound, so the value
is no breakpoint. For , beyond the bound, so
and is not even dyadic. A value that is no
breakpoint has a positive distance to every breakpoint, and the enclosure
width tends to zero as grows, so some certifies it. Values whose
binary logarithm is certainly beyond the range, estimated with
and a safety margin, overflow or underflow without any
arithmetic, so 1e100000000 costs nothing.
Fixed digits. to_decimal_string_ctx(x, d) needs
with . starts from ,
which is within one of the answer, and is corrected by comparing with
, first through directed bounds of the power and, when they
straddle, exactly. The quotient is formed exactly as an integer division when
its operands have at most bits, so ties and exact results are
recognised; otherwise directed enclosures are widened until both ends round
to the same integer, which terminates because such a quotient is neither an
integer nor a half-integer. A carry into a new leading digit
() increments and repeats.
Shortest output. Let be the set of reals that round to under RNE in the context; it is an interval containing . For each digit count , the two -digit decimals next to (truncated and rounded away from zero) are candidates, and a candidate is accepted when parsing it returns , that is when it lies in . Acceptance is monotone in : if the -digit truncation lies in , the -digit truncation satisfies (in magnitude), so it lies in the interval too, and likewise for the upper neighbour. So the least accepted is found by bisection on , an upper bound at which a candidate is always accepted.66 The digit count suffices for round trip (Matula 1968; Goldberg 1991, Theorem 15); the extra digit is a margin for the bisection’s upper end. If both candidates are accepted, the nearer one is chosen, then the even one, which is the nearest decimal of that length. For binary64 this reproduces the host formatter on every value tested.
Certified elementary functions
Problem. For the value is transcendental and must be rounded correctly without knowing it.
Options. Fixed polynomial approximations with a proven error bound (fast, but tied to one precision); Ziv’s strategy of evaluating with an a priori error bound and retrying at a higher precision when the rounding is ambiguous;77 A. Ziv, “Fast evaluation of elementary mathematical functions with correctly rounded last bit”, ACM TOMS 17(3), 1991; for interval evaluation see W. Tucker, Validated Numerics, Princeton 2011, and F. Johansson, “Arb: efficient arbitrary-precision midpoint-radius interval arithmetic”, IEEE Trans. Computers 66(8), 2017. or interval evaluation.
Choice. A Ziv loop whose error bound is not estimated but computed: every elementary function evaluates an enclosure in which every internal operation is rounded downward for and upward for at a working precision . If
the common value is returned, otherwise grows. This is sound by (R2): implies , so equal ends force . The flags agree as well, because overflow, tininess and inexactness are monotone in the same way on one side of zero; the test compares them explicitly instead of relying on this.
The enclosures come from series with rigorous tails and from monotone reductions. For on , the terms satisfy , so after the last summed term
and the code stops once and adds (rounded upward) to the upper sum; the lower sum of positive terms is already a lower bound. Larger arguments are halved times and the result squared times, which is monotone on positive numbers and therefore keeps the enclosure; handles negative arguments. For with the series is
with tail , the bound the code adds. The trigonometric functions
reduce by an enclosure of (from , itself
enclosed by the arctangent series after argument halving) at
bits, so the quadrant
is the same integer at both ends of
the enclosure; otherwise the attempt is repeated at a higher precision. This
is the Payne–Hanek idea realised by brute precision instead of a stored table
of ; its cost grows with , so inputs needing more than
bits are refused with ResourceLimit rather than run for minutes.
Budget. The loop starts at and steps
, at most 12 attempts. For
binary64 the sequence is bits. Ziv’s argument
for termination is that is not a breakpoint of : by
Lindemann–Weierstrass, , , , , and
their inverses are transcendental at every nonzero algebraic (in particular
dyadic) argument other than the trivial exceptions, while breakpoints are
dyadic. The exceptions are filtered before the loop: ,
, , for integral , ,
integral and half-integral arguments of sinpi and cospi,
, for integral , , and so on. For the -scaled functions Niven’s theorem shows
that these are the only dyadic results.88 I. Niven, Irrational Numbers, 1956, Corollary 3.12: if is
rational and is rational, then
; similarly for , and
. The value needs with
denominator 6 or 3, which is not dyadic. A
non-breakpoint has a positive distance to every breakpoint, so a large
enough certifies it. How large must be is the table maker’s dilemma:
no useful a priori bound is known for arbitrary , so the budget is a
resource limit, not a correctness condition. When it runs out the try_*
form reports a CertificationFailure with the stage, the reason and the last
, and the total forms return a quiet NaN with invalid_operation; neither
returns an uncertified value. The pinned MPFR corpus never exhausts it.
One family of exceptions is not filtered on the current branch: pow with a
non-integral exponent other than whose result is nevertheless dyadic,
such as . Under nearest rounding the enclosure still certifies
the right value but inexact is raised; under a directed rounding the
loop cannot certify and returns a CertificationFailure.
Integer powers. pow_int_ctx computes by an addition chain at
bits with
round-to-nearest. Each chain step multiplies two
approximations; if describes the error
structure, then and , so by
induction . The computed value is therefore
with
in Higham’s notation, which is below units in the
last place of the -bit result. The code uses the radius
units (one more factor of two for a negative
power, whose reciprocal adds further factors), builds the interval, and
accepts when both ends round alike, by the same (R2) argument. When 12
doublings do not certify, the exact power is formed and rounded,
so the result is correctly rounded in every case. A power certainly outside
the range is decided first from certified bounds, and powers whose
exact value fits in bits are computed exactly, which also guarantees that
the Ziv path only sees inexact results.
The coefficient kernel
Problem. Precision costs integer multiplication and division of -bit numbers, and ranges from 1 to .
Choice. BinCoeff stores up to 128 bits inline and larger values as
little-endian 32-bit limbs (a host bigint on JavaScript), and dispatches
on the shorter operand length in limbs:
| Product | Native | LLVM | Wasm, Wasm-GC |
|---|---|---|---|
| schoolbook below | 96 | 96 | 96 |
| Karatsuba from | 96 | 96 | 96 |
| Toom-3 from | 2048 | 2048 | 4096 |
| two-prime NTT multiply from | 2048 | 2048 | 4096 |
| NTT square from | 768 | 768 | 3072 |
| recursive square from | 512 | 768 | 768 |
Sparse operands (few nonzero limbs) use a sparse product, and operands with limbs are cut into -limb blocks. Division uses a one-limb loop, Knuth’s algorithm D below 48 divisor limbs, Burnikel–Ziegler recursion from 48 and a Newton reciprocal from 1024; GCD switches from the binary (Stein) algorithm to Lehmer batches above four limbs. The thresholds are measured, per target, by the benchmark suite; they are policy, not semantics.
Why exactness is preserved. Schoolbook, Karatsuba and Toom-3 evaluate integer polynomial identities, for example
and Toom-3 (evaluation at ) interpolates with exact divisions by 2 and 3 of signed intermediates known to be multiples, so they are exact integer computations. The NTT is the only modular step. It splits each operand into 16-bit digits, so each coefficient of the digit convolution is at most
for transform lengths up to . It computes the convolution modulo the primes and , both of which have -th roots of unity, and recombines by the Chinese remainder theorem, which is unique in with . So the recombined coefficients are the exact integers. The length check precedes every transform; a longer product uses overlapping blocks of admissible length or falls back to Toom-3. Division paths return with and by construction; the Newton path corrects its approximate quotient with the remainder and aborts if more than two corrections would be needed, which would indicate a bug rather than a numerical event. Because all paths compute the same integers, the choice of algorithm cannot change any rounded result, flag or encoding.
Ordering NaN in compare
Problem. MoonBit’s Compare trait asks for a three-way comparison that
sorting and ordered maps can rely on. IEEE comparison is a partial order:
NaN is unordered with everything, itself included.
Options. (1) Abort on NaN, as earlier versions did; every sort of data
that might contain a NaN then becomes a crash. (2) Use IEEE totalOrder,
which is total but distinguishes and puts negative NaNs below
, so compare would disagree with numerical equality on zeros.
(3) Keep the numerical order on numbers and put all NaNs in one class above
it.
Choice. Option (3). Define the key for a number and
, ordered lexicographically; compare(x, y)
is the comparison of and , with and mapped to
the same number. A comparison of keys in a totally ordered set is reflexive,
transitive and total, so compare is a total preorder; it is not
antisymmetric ( and , or two NaNs with different payloads, compare
equal but are different values), which Compare does not require. The cost is
that nan > 1 is true under <, so code that needs IEEE semantics must use
compare_checked (error on NaN), compare_quiet / compare_signaling
(four-valued, with flags) or total_order. Structural == stays the derived
Eq, because it is the only equality that is a congruence for every method
(precision and payload included).
Correctness / invariants
- Canonical form. Every finite value produced by the API has odd or , and its precision; stored exponents never saturate (a saturated exponent is classified as overflow or underflow first).
- Correct rounding. For every arithmetic operation, conversion and
elementary function and every context, the returned finite value equals
for the exact real result , with the range rules above. By
(R1), and no flag is raised whenever ;
round_ctxis idempotent. - Flags.
inexactiff ;overflowimpliesinexact;underflowiff tiny (per the context rule) and inexact;division_by_zeroonly for an exact infinite result of finite operands;invalid_operationiff a quiet NaN was produced from non-NaN operands or a signaling NaN was consumed.combineis associative, commutative and idempotent. - Error model. Consequently, in the normal range, for nearest and for directed rounding, with the absolute term (respectively ) below , and subnormal sums and differences are exact.
- Monotonicity. Each operation is monotone in each argument where the
real function is, because it is with monotone; in
particular RD and RU results bracket the exact value, which
ball_floatandsqrt_bounds_for_precisionrely on. - Exactness theorems.
remainder,scalebin the normal range,copy_sign,neg,abs,logb,to_integral_*and decoding are exact;fma(a, b, -RN(ab))is exact without underflow. - Complexity. Addition is linear in the operand length (and independent
of the exponent gap, by the far-operand rule); multiplication follows the
kernel table, to ; division and square root cost a
constant number of multiplications of the same size at large ;
remaindercosts modular multiplications; an elementary function evaluates its series at the working precision , and because grows geometrically the total cost of all attempts is within a constant factor of the last one.
The longer proofs (the far-operand addition rule, nextUp, the remainder
reduction, the Ziv acceptance test and the NTT bound) are collected in the
attachment.
Alternatives rejected
- Host
Doublefor anything butfrom_double. Routing binary16, binary32 or binary128 throughDoubledouble-rounds, loses signaling NaNs on some targets and cannot represent binary128 at all. Interchange encoding is done onBinCoeffbit patterns instead. - A fixed number of guard bits. Three guard bits suffice for addition of two -bit operands, but not for division, square root, conversions from decimal or operands wider than the context. Deciding from exact integer data (round, sticky, remainder sign, midpoint comparison) works for all of them with one finalizer.
- Rounding to bits, then to the subnormal grid. This double rounding produces wrong subnormal results; the finalizer shifts once to the coarser of the two positions.
- Ziv with an estimated error bound. It requires a separate error analysis for every function and every reduction, and a mistake in it silently returns a wrong last bit. Outward-rounded enclosures make the bound a computed quantity, at the cost of evaluating every operation twice.
- Global flags and rounding state. IEEE 754 describes flags as sticky
global state. A returned
BinaryFlagsvalue composes with pure code, concurrent code and theResultstyle of@lf_arith, andcombinerecovers the sticky behaviour where wanted. compareaborting on NaN, orcompareastotalOrder. See Ordering NaN incompare.
Boundaries
bin_float deliberately does not:
- provide interval or ball arithmetic: enclosures are internal to the
certification loops;
ball_floatbuilds midpoint–radius arithmetic on top ofBinFloat; - implement IEEE 754 alternate exception handling (traps, substitution) or sticky global flags: flags are returned values;
- implement decimal floating-point (
decimal,decimal_gda) or the non-binary IEEE operations on them; - promise any NaN payload for a newly generated NaN (it uses payload 0), or propagate payloads of more than one input;
- guarantee completion of an elementary function within any time for every input: certification has a budget, and an exhausted budget is reported, not hidden;
- expose limb layout, thresholds or transform parameters: they may change without notice as long as every result, flag and encoding stays the same;
- claim conformance beyond the finite corpus recorded in conformance.
Footnotes
-
IEEE Std 754-2019, IEEE Standard for Floating-Point Arithmetic: clause 3 (formats), 4.3 (rounding-direction attributes), 5 (operations), 6 (infinities, NaNs, signed zero), 7 (default exception handling). ↩
-
N. J. Higham, Accuracy and Stability of Numerical Algorithms, 2nd ed., SIAM 2002, §2.2; D. Goldberg, “What every computer scientist should know about floating-point arithmetic”, ACM Computing Surveys 23(1), 1991. ↩
-
J.-M. Muller et al., Handbook of Floating-Point Arithmetic, 2nd ed., Birkhäuser 2018, §2.1 and §4.3. ↩
-
Muller et al., Handbook of Floating-Point Arithmetic, §5.3 and §7.6. ↩
-
T. J. Dekker, “A floating-point technique for extending the available precision”, Numerische Mathematik 18, 1971; Muller et al., §4.4. ↩
-
The digit count suffices for round trip (Matula 1968; Goldberg 1991, Theorem 15); the extra digit is a margin for the bisection’s upper end. ↩
-
A. Ziv, “Fast evaluation of elementary mathematical functions with correctly rounded last bit”, ACM TOMS 17(3), 1991; for interval evaluation see W. Tucker, Validated Numerics, Princeton 2011, and F. Johansson, “Arb: efficient arbitrary-precision midpoint-radius interval arithmetic”, IEEE Trans. Computers 66(8), 2017. ↩
-
I. Niven, Irrational Numbers, 1956, Corollary 3.12: if is rational and is rational, then ; similarly for , and . The value needs with denominator 6 or 3, which is not dyadic. ↩