Skip to main content

Module campbell

Module campbell 

Source
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: like consttime_cmove, but the flag is computed by smearing every set bit of m down 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 of m through a timing side channel.
consttime_cmove
Modified port of uniformbinary64_consttime: like fast, but the zero-m event is branchless, with the flag computed as m != 0.
fast
Port of uniformbinary64_fast: a correctly rounded (to nearest) uniform real in [0 . . 1], branching on the 2⁻⁶⁴-probability zero-m event.
fastdet
Port of Campbell’s uniformbinary64_fastdet, the deterministic core of this module: turns an exponent scale f ∈ {2⁻⁶⁴, 2⁻¹²⁸}, a geometric word m and a significand word u into a correctly rounded (to nearest) uniform binary64.
real
Port of random_real from random_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 nearest f64, 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.