UniformFloat

r.UniformFloat()r.\operatorname{UniformFloat}()

Draw a uniform random value in [0,1)[0, 1) using generator rr. UniformFloat\operatorname{UniformFloat} is the primitive draw; all other randomization functions and distribution samplers build on top of it.

  • DistributionUniform(0,1)\underline{\operatorname{Uniform}}(0, 1)
  • Range[0,1)[0, 1) (includes 0, excludes 1)
  • Precision — 53-bit mantissa (2532^{53} distinct values)
  • ComplexityO(1)O(1) per draw

Properties

  • Determinism same generator state produces same value
  • Independence successive draws are uncorrelated
  • Uniformity all representable values in [0,1)[0, 1) equally likely

Example (conceptual)

  • CallRng("demo").UniformFloat() (conceptual name; see mapping below)
  • Repeat — 10 successive calls produce 10 independent values

Implementation names

LanguageMethod
C#UniformDouble()
GoUniformFloat64()
KotlinuniformDouble()
Rustuniform_f64()
Pythonuniform_float()
Runiform_float()
TypeScriptuniformFloat()

UniformFloat\operatorname{UniformFloat} is the fundamental operation of the random number generator. All other randomization functions — Sample\operatorname{Sample}, Shuffle\operatorname{Shuffle}, Resample\operatorname{Resample}, and the distribution samplers — are built on top of uniform draws. See Naming for why the toolkit uses the name UniformFloat\operatorname{UniformFloat} instead of the traditional .Next().

Algorithm

Generator Core

The core random number generator uses the xoshiro256++ algorithm (see Blackman & Vigna 2021), a member of the xoshiro/xoroshiro family developed by David Blackman and Sebastiano Vigna. This algorithm was selected for several reasons:

  • Quality: passes all tests in the BigCrush test suite from TestU01
  • Speed: extremely fast due to simple bitwise operations (shifts, rotations, XORs)
  • Period: period of 225612^{256} - 1, sufficient for parallel simulations
  • Adoption: used by .NET 6+, Julia, and Rusts rand crate

The generator maintains a 256-bit state (s0,s1,s2,s3s_0, s_1, s_2, s_3) and produces 64-bit outputs. Each step updates the state through a combination of XOR, shift, and rotate operations.

Seed Initialization

Converting a single seed value into the full 256-bit state requires a seeding algorithm. The toolkit uses SplitMix64 (see Steele et al. 2014) for this purpose:

xx+0x9e3779b97f4a7c15z(xxor(x30))×0xbf58476d1ce4e5b9z(zxor(z27))×0x94d049bb133111eboutputzxor(z31)\begin{aligned} x &\leftarrow x + \text{0x9e3779b97f4a7c15} \\ z &\leftarrow (x \operatorname{xor} (x \gg 30)) \times \text{0xbf58476d1ce4e5b9} \\ z &\leftarrow (z \operatorname{xor} (z \gg 27)) \times \text{0x94d049bb133111eb} \\ \text{output} &\leftarrow z \operatorname{xor} (z \gg 31) \end{aligned}

Four consecutive outputs from SplitMix64 initialize the xoshiro256++ state (s0,s1,s2,s3s_0, s_1, s_2, s_3). This approach provides high-quality initial states from simple integer seeds.

String Seeds

For named experiments (e.g., Rng(experiment-1)\operatorname{Rng}(\text{experiment-1})), string seeds are converted to integers using FNV-1a hash (see Fowler et al. 1991):

hash0xcbf29ce484222325(offset basis)for each byteb:hash(hashxorb)×0x00000100000001b3(FNV prime)\begin{aligned} \text{hash} &\leftarrow \text{0xcbf29ce484222325} \quad \text{(offset basis)} \\ \text{for each byte} b: \quad \text{hash} &\leftarrow (\text{hash} \operatorname{xor} b) \times \text{0x00000100000001b3} \quad \text{(FNV prime)} \end{aligned}

This enables meaningful experiment identifiers while maintaining determinism.

UniformFloat Generation

To generate uniform values in [0,1)[0, 1), the upper 53 bits of a 64-bit output are used:

r.UniformFloat()=(next()11)×253r.\operatorname{UniformFloat}() = (\text{next()} \gg 11) \times 2^{-53}

The 53-bit mantissa of IEEE 754 double precision ensures all representable values in [0,1)[0, 1) are reachable.

UniformInt Mapping

UniformInt\operatorname{UniformInt} maps a uniform 64-bit value into [a,b)[a, b) using modulo reduction. Ranges that do not divide 2642^{64} introduce a slight bias (acceptable for simulation, not for cryptographic use).

Numerical Constants

Distribution sampling requires handling edge cases where floating-point operations would be undefined. Two constants are used across all language implementations:

Machine Epsilon (ϵmach\epsilon_{\text{mach}}): The smallest ϵ\epsilon such that 1+ϵ11 + \epsilon \neq 1 in float64 arithmetic.

ϵmach=2522.22×1016\epsilon_{\text{mach}} = 2^{-52} \approx 2.22 \times 10^{-16}

Used when U=1U = 1 to avoid ln(0)\ln(0) or division by zero in inverse transform sampling.

Smallest Positive Subnormal (ϵsub\epsilon_{\text{sub}}): The smallest positive value representable in IEEE 754 binary64.

ϵsub=210744.94×10324\epsilon_{\text{sub}} = 2^{-1074} \approx 4.94 \times 10^{-324}

Used when U=0U = 0 to avoid ln(0)\ln(0) in transforms that take a logarithm.

All language implementations use the same literal values for these constants (not language-specific builtins like Number.EPSILON or f64::EPSILON) to ensure bit-identical outputs across languages.

Distribution Sampling

All distribution samplers consume one or more UniformFloat\operatorname{UniformFloat} draws. The specific transforms are documented on the corresponding distribution pages.

Notes

Most programming languages expose the primary PRNG operation as .Next(), .random(), or rand() — a method name that describes the mechanism (advance the internal state and return a value) rather than the result (a uniformly distributed number on [0,1)[0, 1)).

This toolkit names the operations UniformFloat\operatorname{UniformFloat} and UniformInt\operatorname{UniformInt} — combining the distribution name with the return type. The reasons are both pedagogical and practical. In actual code the method names are language-specific and type-suffixed; see the UniformFloat and UniformInt pages for the mapping.

The name communicates the contract. Calling r.UniformFloat()r.\operatorname{UniformFloat}() immediately tells the reader what distribution the returned value follows and what type it produces. Calling r.Next() says only that something comes next; the distribution, range, and precision are left to documentation. In a library that manipulates multiple distributions (Additive\underline{\operatorname{Additive}}, Multiplic\underline{\operatorname{Multiplic}}, Exp\underline{\operatorname{Exp}}, Power\underline{\operatorname{Power}}, Uniform\underline{\operatorname{Uniform}}), naming the uniform draw explicitly makes it a peer of the other distributions rather than a special primitive hidden behind a generic verb.

The name prevents a category error. When random() returns a value in [0,1)[0, 1), users sometimes treat it as a random number without recognizing that it samples from a specific distribution. Making the distribution explicit in the name reinforces that Uniform\underline{\operatorname{Uniform}} is one choice among many and that other distributions require different transformations.

The name preserves the URL namespace. Using UniformFloat\operatorname{UniformFloat} for the function frees /uniform for the Uniform\underline{\operatorname{Uniform}} distribution page, avoiding ambiguity between the function (which draws a single value) and the distribution family (which defines the parametric model).

Composition becomes self-documenting. When a distribution is built from uniform draws, the code reads naturally as take UniformFloat\operatorname{UniformFloat} draws and apply a transformation, keeping the distribution explicit. Replacing UniformFloat\operatorname{UniformFloat} with .Next() in these descriptions obscures the mathematical structure.

Precedent. Scientific computing libraries (NumPys random.uniform, Rs runif, Julias rand(Uniform())) already use uniform when the distribution matters. The toolkit follows this convention consistently: every random draw is named after its distribution, starting with the simplest one.

References

Scrambled Linear Pseudorandom Number Generators
Blackman, David, Vigna, Sebastiano (2021)
ACM Transactions on Mathematical Software
Fast Splittable Pseudorandom Number Generators
Steele, Guy L., Lea, Doug, Flood, Christine H. (2014)
OOPSLA ‘14: Proceedings of the 2014 ACM International Conference on Object Oriented Programming Systems Languages & Applications
FNV Hash
Fowler, Glenn, Noll, Landon Curt, Vo, Kiem-Phong (1991)