Skip to main content

real

Function real 

Source
pub fn real(bits: impl FnMut() -> u64) -> f64
Expand description

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.

This documentation differs from the comments in the C original, which claims to reach every float in [0 . . 1] and to return 0 only when the result is guaranteed to round to zero: the all-zeros cutoff fires one word too early (after 16 rather than 17 zero words) discarding continuations as large as ≈2⁻¹⁰²⁴ that would round to smaller subnormals. This is a minor bug we found while porting and reported to the author; it affects an event of probability 2⁻¹⁰²⁴, and the code below is left faithful to the original.

Consumes one 64-bit word, plus one more with probability 1/2 (when the first word has leading zeros), plus one word per 64 leading zero bits. The expected number of words per call is ≈1.5.

The C original scales by ldexp(significand, exponent); Rust has no ldexp in the standard library, and a single multiplication cannot replace it, since 2^exponent can be as small as 2⁻¹⁰⁸⁷, which is not representable. The port multiplies by 2⁻⁹⁶⁰ first (exact, since the intermediate result stays normal) and then by 2^(exponent + 960), which is always representable, so the result is rounded once, exactly as in ldexp. On x86-64 compiled with AVX-512F the port uses instead the hardware ldexp (a single vscalefsd instruction) via inline assembly.