Expand description
Taylor R. Campbell’s correctly rounded uniform doubles.
A Rust port of binary64fast.c (Campbell, 2014–2026) and of the
random_real function of random_real.c (Campbell, 2014). These
functions return an f64 distributed as a uniform
real in [0 . . 1] correctly rounded to nearest. The binary64fast.c
functions (fast and the const-time variants) stop after two exponent
words, so they reach every float in [2⁻¹²⁸ . . 1], each with
probability equal to the measure of the reals that round to it, except
that the reals below 2⁻¹²⁸ (probability 2⁻¹²⁸) are folded into the bottom
binade. In particular, 0 never occurs: real keeps consuming words,
and reaches every float in [2⁻¹⁰²⁴ . . 1], plus 0 (see its documentation
for why the smaller subnormals cannot occur).
Two variants handle the zero-m event without data-dependent branching, for
use where timing side channels matter; they unconditionally consume three
words per call. The cmov variant is a modification of mine in which the
“bit smearing“ technique of the original C is replaced by a comparison that
the compiler can turn into a conditional-move instruction (Taylor does not
want to rely on the compiler for the absence of tests, but the smearing is
much slower.)
If you compare generated code with older copies of binary64fast.c you
might find a signed where an unsigned integer-to-double conversion
instruction was present: Taylor fixed the code after I reported the
possibility of a branchy unsigned conversion on pre-AVX-512 x86.
Functions§
- consttime
- Port of
uniformbinary64_consttime_smear: likeconsttime_cmove, but the flag is computed by smearing every set bit ofmdown to bit 0, so it is branchless at the source level, independently of the compiler. This is the variant Taylor prefers for security-sensitive uses, since no compiler-inserted test can leak the (secret) value ofmthrough a timing side channel. - consttime_
cmove - Modified port of
uniformbinary64_consttime: likefast, but the zero-mevent is branchless, with the flag computed asm != 0. - fast
- Port of
uniformbinary64_fast: a correctly rounded (to nearest) uniform real in [0 . . 1], branching on the 2⁻⁶⁴-probability zero-mevent. - fastdet
- Port of Campbell’s
uniformbinary64_fastdet, the deterministic core of this module: turns an exponent scalef∈ {2⁻⁶⁴, 2⁻¹²⁸}, a geometric wordmand a significand worduinto a correctly rounded (to nearest) uniform binary64. - real
- Port of
random_realfromrandom_real.c: interprets an unbounded stream of random bits as the binary expansion of a real number in [0 . . 1] and rounds it to the nearestf64, with a sticky bit avoiding ties. Every float in [2⁻¹⁰²⁴ . . 1] is reachable; 0 is returned after 1024 zero bits (probability 2⁻¹⁰²⁴, i.e., only if the source is broken), and the subnormals below 2⁻¹⁰²⁴ cannot occur.