rand

repository·master·Indexed 22 days ago

https://github.com/rust-random/rand

A comprehensive ecosystem of Rust crates for generating pseudo-random numbers, sampling from various distributions, and performing random sequence operations. Version 0.10.2 provides high-level convenience APIs like `rand::rng()` and low-level generator traits based on `rand_core::RngCore`. It supports a variety of generators (fast, cryptographically-secure, and specialized), sampling distributions (Uniform, StandardUniform, Alphanumeric), and sequence operations such as `choose` and `shuffle`.

Tokens
11.3K
Snippets
36
Records
66
Agent score
84%

What's inside rand

  1. Overview of the Rand ecosystem

    master

    Rand is a collection of crates providing (pseudo-)random number generators (RNGs) and sampling distributions. It is built upon the rand_core::RngCore trait and offers a variety of generator types:

    • Fast, general-purpose generators: Available in rand::rngs.
    • Strong/Cryptographically-secure generators: Such as those provided by the chacha20 crate.
    • Specialized generators: Including rand_xoshiro, rand_pcg, rand_sfc, and others.
    • Convenience API: rand::rng() provides an asymptotically-fast, automatically-seeded, and reasonably strong generator available on all std targets.

    Key capabilities include:

    • Sampling: StandardUniform and Uniform distributions, plus non-uniform distributions via rand_distr or statrs.
    • Random Processes: Sequence operations like choose and shuffle via rand::seq traits.
    • Portability: Support for reproducible output and #[no_std] compatibility (partial).
  2. Sample from a `usize` range

    master

    The rand crate provides optimized sampling for usize via the UniformUsize backend.

    On 64-bit architectures, if the requested range fits within a u32, the sampler uses 32-bit logic for better performance and portability. If the range exceeds u32::MAX, it automatically switches to 64-bit sampling logic.

    Note that Uniform::new(low, high) for usize requires low < high, while Uniform::new_inclusive(low, high) requires low <= high.

  3. Configure Rand crate features

    master

    Rand uses Cargo features to manage dependencies and functionality.

    Default Features

    • std: Enables functionality dependent on the standard library.
    • alloc: (Implied by std) Enables functionality requiring an allocator (required for many sequence and distribution functions).
    • sys_rng: Enables rand::rngs::SysRng (via getrandom).
    • std_rng: Enables rand::rngs::StdRng (via chacha20).
    • thread_rng: (Implies std, std_rng, sys_rng) Enables rand::rngs::ThreadRng and the rand::rng() function.

    Optional Features

    • chacha: Enables rand::rngs::{ChaCha8Rng, ChaCha12Rng, ChaCha20Rng}.
    • simd_support (experimental): Enables sampling of SIMD values (requires nightly Rust due to std::simd).
    • unbiased: Uses unbiased sampling for algorithms that support it (e.g., Uniform distribution). Note that this may affect reproducibility. By default, bias affecting no more than one in $2^{48}$ samples is accepted.
  4. Understand bias in integer uniform distributions

    master

    By default, integer uniform distributions in rand may have a small bias unless the unbiased feature flag is enabled. The magnitude of this bias depends on the bit-width of the type being sampled:

    • i8 and u8: 1 in $2^{56}$
    • i16 and u16: 1 in $2^{48}$
    • i32 and u32: 1 in $2^{96}$
    • i64 and u64: 1 in $2^{64}$
    • i128 and u128: 1 in $2^{128}$

    To ensure perfectly uniform sampling, enable the unbiased feature in your Cargo.toml.

  5. Use SmallRng for fast, non-cryptographic random number generation

    master

    SmallRng is a small-state, fast, non-cryptographic, and non-portable Pseudo-Random Number Generator (PRNG). It is designed for performance and low memory usage rather than security.

    Key Properties

    • Non-cryptographic: Output is easy to predict and should not be used for security-sensitive applications.
    • Non-portable: The underlying algorithm may change between library versions or differ based on the platform (e.g., using Xoshiro256PlusPlus on 64-bit and Xoshiro128PlusPlus on 32-bit). For portable generators, use the rand_pcg or rand_xoshiro crates.
    • Fast: Optimized for both bulk generation and single values.
    • Small state: Uses minimal memory (16-32 bytes depending on the platform).

    Seeding and Construction

    SmallRng implements the SeedableRng trait. You can initialize it in several ways:

    1. Automatic seeding: Use rand::make_rng() to get a unique seed.
    2. Deterministic integral seed: Use seed_from_u64 to create a generator from a u64 value. This uses an internal hash function to expand the input into a high-quality seed.
    3. Deterministic byte seed: Use from_seed with a [u8; 32] array.

    Generation

    SmallRng implements the Rng and TryRng traits, allowing you to generate various types of random values.

  6. Use SIMD for bulk integer sampling

    master
    If the simd_support feature is enabled, UniformInt supports sampling Simd types. This allows for generating multiple random integers in parallel across multiple lanes. The sampler uses a loop to replace only the specific lanes that fail the uniformity threshold, which helps maintain performance even when rejections occur.
  7. Use StdRng for cryptographically secure random number generation

    master

    StdRng is a strong, fast, and cryptographically secure pseudo-random number generator (CSPRNG). It is designed for high-quality randomness and is suitable for security-sensitive applications.

    Key Characteristics:

    • CSPRNG: Provides statistically good quality randomness and is unpredictable.
    • Fast (Amortized): Optimized for bulk generation, though individual method call costs may vary due to internal buffering.
    • Non-portable: The underlying algorithm (currently ChaCha12) may change in future versions, and results may be platform-dependent. If you require identical results across different platforms or versions, use the chacha20 crate directly.

    Seeding and Construction:

    • Most Secure: Seed directly from the OS using try_from_rng with SysRng.
    • Convenient: Use rand::make_rng() or rand::rng() for faster initialization.
    • Note: seed_from_u64 is provided via the SeedableRng trait but is not suitable for security-critical use cases. Even with a fixed seed, the output is not guaranteed to be portable across library versions.
  8. How IndexedRandom, IndexedMutRandom, and SliceRandom relate

    master

    The rand crate provides a hierarchy of traits for random operations on indexable collections:

    1. IndexedRandom: Provides read-only sampling methods like choose, choose_iter, sample, and sample_weighted. It is implemented for any type that supports Index<usize> and has a len() method.
    2. IndexedMutRandom: Extends IndexedRandom for types that also implement IndexMut<usize>. It adds methods for mutable sampling, such as choose_mut and choose_weighted_mut.
    3. SliceRandom: Extends IndexedMutRandom specifically for slices ([T]). It adds high-level permutation methods like shuffle and partial_shuffle.
  9. Compare floating-point distributions: StandardUniform, OpenClosed01, and Open01

    master

    When generating random floats, choose the distribution based on the required interval:

    DistributionIntervalDescription
    StandardUniform[0, 1)Includes 0, excludes 1. Uses the multiplicative method.
    OpenClosed01(0, 1]Excludes 0, includes 1. Uses the multiplicative method.
    Open01(0, 1)Excludes both 0 and 1. Uses a transmute-based method.
    UniformArbitrarySamples from a user-specified range.
  10. How `IndexVec` and sampling functions work together

    master

    The rand crate uses IndexVec as a specialized container for sampling results. When you call sample or sample_weighted, the crate performs the sampling logic and stores the resulting indices in an IndexVec. This allows the crate to:

    1. Optimize Storage: Use u32 instead of usize where possible to reduce memory footprint and improve cache locality.
    2. Abstract Platform Differences: Provide a consistent interface for both 32-bit and 64-bit architectures.
    3. Delay Allocation: Avoid converting to a full Vec<usize> until the user explicitly calls .into_vec() or iterates over it.

    To use the results of a sampling operation, you typically iterate over the IndexVec directly or convert it to a Vec<usize> if you need to pass it to other APIs.

  11. Use the RngExt trait for random number generation

    master

    The RngExt trait provides a high-level user interface for Random Number Generators (RNGs). It is automatically implemented for any type that implements the Rng trait. To use these extension methods, you must bring the trait into scope using use rand::RngExt; or use rand::prelude::*;.

    Generic Usage Patterns

    When writing functions that accept an RNG, use one of the following patterns:

    1. For mutable references (Recommended): fn foo<R: Rng + ?Sized>(rng: &mut R) This is the most flexible pattern as it supports both sized types and trait objects (&mut dyn Rng).

    2. For consuming the RNG: fn foo<R: Rng>(rng: R) This allows the argument to be consumed directly without a &mut, but inside the function, you may need to explicitly pass references to distribution sampling methods.

    use rand::{Rng, RngExt};
    
    fn foo<R: Rng + ?Sized>(rng: &mut R) -> f32 {
        rng.random()
    }
    
    # let v = foo(&mut rand::rng());