#Random

    Pseudo-random number generation based on the ChaCha8 stream cipher. Provides unbiased generation of integers, floats, booleans, and big integers, as well as Fisher-Yates shuffling.

    #Overview

    The Rand type wraps a Source trait object that produces 64-bit random values. By default, Rand::new() uses a ChaCha8 cipher seeded from platform entropy when available, and falls back to the default fixed seed on unsupported targets. For reproducible results, use Rand::chacha8(seed~) with the same 32-byte seed; for distinct reproducible streams, supply different seeds.

    #Create

    Create a generator with the default ChaCha8 source:

    ///|
    test {
    let r = @random.Rand::new()
    inspect(r.uint(limit=100) < 100, content="true")
    }

    Supply a custom 32-byte seed for a different (but reproducible) stream:

    ///|
    test {
    let r = @random.Rand::chacha8(seed=b"0123456789abcdef0123456789abcdef")
    let a = r.int()
    let r2 = @random.Rand::chacha8(seed=b"0123456789abcdef0123456789abcdef")
    let b = r2.int()
    @test.assert_eq(a, b) // same seed → same sequence
    }

    #Generating Integers

    int(), uint(), int64(), and uint64() each accept an optional limit parameter. When omitted (or zero), the full non-negative range is returned. When provided, the result is in [0, limit) with no modulo bias.

    ///|
    test {
    let r = @random.Rand::new()
    // full range
    let _ : Int = r.int() // [0, 2^31)
    let _ : UInt = r.uint() // [0, 2^32)
    let _ : Int64 = r.int64() // [0, 2^63)
    let _ : UInt64 = r.uint64() // [0, 2^64)
    // bounded
    let die = r.int(limit=6) // [0, 6)
    inspect(die >= 0 && die < 6, content="true")
    let pct = r.uint(limit=100U)
    inspect(pct < 100U, content="true")
    }

    #Generating Floats

    double() returns a value in [0.0, 1.0) with 53-bit precision. float() returns a value in [0.0, 1.0) with 24-bit precision.

    ///|
    test {
    let r = @random.Rand::new()
    let d = r.double()
    inspect(d >= 0.0 && d < 1.0, content="true")
    let f = r.float()
    inspect(f >= (0.0 : Float) && f < (1.0 : Float), content="true")
    }

    Pass min and max to double() or float() for an arbitrary half-open interval. Non-unit intervals use Goualard's gamma-section algorithm: they select uniformly from a fixed grid whose step is the larger endpoint spacing. Grid values are one step apart, except for a possible shorter gap at the included lower bound. In contrast, scaling a value from [0.0, 1.0) with min + (max - min) * x can bias the result or return the open upper bound because of intermediate rounding.

    ///|
    test {
    let r = @random.Rand::new()
    let d = r.double(min=-10.0, max=10.0)
    inspect(d >= -10.0 && d < 10.0, content="true")
    let f = r.float(min=-10.0F, max=10.0F)
    inspect(f >= -10.0F && f < 10.0F, content="true")
    }

    To prevent quarter-scaling a bound into the subnormal range, these methods reject non-zero bounds whose magnitude is below four times the smallest positive normal value for the corresponding type. Zero remains a valid bound. The selected grid step may still be subnormal, where IEEE 754 gradual underflow preserves it exactly. double() additionally rejects an interval if scaling either bound by that step would underflow; float() performs the setup calculation exactly in Double precision.

    #Boolean

    boolean() returns true or false with equal probability.

    ///|
    test {
    let r = @random.Rand::new()
    let _ : Bool = r.boolean()
    }

    #Shuffling

    shuffle(n, swap) performs a Fisher-Yates shuffle over n elements using the provided swap callback.

    ///|
    test {
    let r = @random.Rand::new()
    let a = [1, 2, 3, 4, 5]
    r.shuffle(a.length(), fn(i, j) {
    let t = a[i]
    a[i] = a[j]
    a[j] = t
    })
    a.sort()
    @test.assert_eq(a, [1, 2, 3, 4, 5]) // same elements, just reordered
    }

    #BigInt

    Generate a random non-negative BigInt with at most the given number of bits (leading zero bits are allowed):

    ///|
    test {
    let r = @random.Rand::new()
    let big = r.bigint(128)
    inspect(big >= 0N, content="true")
    }

    #Custom Source

    Implement the Source trait to plug in your own RNG backend. The trait requires a single method next(Self) -> UInt64.

    ///|
    struct MySource {
    mut value : UInt64
    }

    ///|
    impl @random.Source for MySource with fn next(self) -> UInt64 {
    self.value = self.value * 6364136223846793005UL + 1UL
    self.value
    }

    ///|
    test {
    let gen : MySource = { value: 42, }
    let r = @random.Rand::new(generator=gen as &@random.Source)
    let _ = r.uint64()
    }

    Source

    pub(open) trait Source {
    fn next(Self) -> UInt64
    }

    The [Source] trait defines a method to generate random numbers.

    Rand

    type Rand

    Rand is a pseudo-random number generator (PRNG) that provides various methods to generate random numbers of different types.

    Rand::bigint

    fn Rand::bigint(self : Rand, bits : Int) ->
    BigInt

    Generates a random non-negative BigInt with at most bits bits. Leading zero bits are allowed; bits = 0 returns zero.

    Parameters:

    • self : The random number generator to draw the bits from.
    • bits : The desired number of bits in the generated number.

    Example:

    test {
    let rand = @random.Rand::new()
    let n = rand.bigint(8) // Generate random 8-bit number
    inspect(n.bit_length() <= 8, content="true")
    }

    Rand::boolean

    fn Rand::boolean(self : Rand) -> Bool

    [boolean] returns a random boolean value (true or false).

    Rand::chacha8

    fn Rand::chacha8(seed? : Bytes) -> Rand

    Create a new random number generator with [seed]. @alert unsafe "Panic if seed is not 32 bytes long"

    Rand::double

    fn Rand::double(self : Rand, min? : Double, max? : Double) -> Double

    Returns a pseudo-random Double in the half-open interval [min, max). The bounds default to 0.0 and 1.0; that interval uses the original direct 53-bit construction. Other intervals use Goualard's corrected gamma-section algorithm.

    Example

    test {
    let rand = @random.Rand::chacha8()
    let value = rand.double(min=-2.0, max=3.0)
    inspect(value >= -2.0 && value < 3.0, content="true")
    }

    Panics

    Panics if either bound is not finite, if min >= max, or if a non-zero bound has magnitude below 4 * @double.min_positive. It also panics if dividing either bound by the selected gamma step would underflow.

    Rand::float

    fn Rand::float(self : Rand, min? : Float, max? : Float) -> Float

    Returns a pseudo-random Float in the half-open interval [min, max). The bounds default to 0.0F and 1.0F; that interval uses the original direct 24-bit construction. Other intervals use Goualard's corrected gamma-section algorithm.

    Example

    test {
    let rand = @random.Rand::chacha8()
    let value = rand.float(min=-2.0F, max=3.0F)
    inspect(value >= -2.0F && value < 3.0F, content="true")
    }

    Panics

    Panics if either bound is not finite, if min >= max, or if a non-zero bound has magnitude below 4 * @float.min_positive.

    Rand::int

    fn Rand::int(self : Rand, limit? : Int) -> Int

    [int] Return a non-negative pseudo-random 31-bit integer as an Int in the range [0, 2^31) or [0, limit) if limit is provided.

    Arguments

    • limit - The upper bound (exclusive) of the random number to be generated (Optional). When limit is 0, the range is [0, 2^31).

    Rand::int64

    fn Rand::int64(self : Rand, limit? : Int64) -> Int64

    [int64] returns a non-negative pseudo-random 63-bit integer as an Int64 in the range [0, 2^63)

    Arguments

    • limit - The upper bound (exclusive) of the random number to be generated (Optional). When limit is 0, the range is [0, 2^63).

    Rand::new

    fn Rand::new(generator? : &Source) -> Rand

    Create a random number generator with the supplied [Source]. Without a source, seeds ChaCha8 from platform entropy when available, falling back to the fixed default seed if entropy is unavailable.

    Rand::shuffle

    fn Rand::shuffle(self : Rand, limit : Int, swap : (Int, Int) -> Unit) -> Unit

    [shuffle] shuffles the first n elements of an array using the Fisher-Yates shuffle algorithm. The limit should not be negative.

    Example

    test {
    let r = @random.Rand::new()
    let a : FixedArray[Int] = [1, 2, 3, 4, 5]
    r.shuffle(a.length(), (i : Int, j : Int) => {
    let t = a[i]
    a[i] = a[j]
    a[j] = t
    })
    }

    Rand::uint

    fn Rand::uint(self : Rand, limit? : UInt) -> UInt

    [uint] returns a non-negative pseudo-random 32-bit integer as a Uint in the range [0, 2^32) or [0, limit) if limit is provided.

    Arguments

    • limit - The upper bound (exclusive) of the random number to be generated (Optional). When limit is 0, the range is [0, 2^32).

    Rand::uint64

    fn Rand::uint64(self : Rand, limit? : UInt64) -> UInt64

    [uint64] returns a non-negative pseudo-random 64-bit integer as a Uint64 in the range [0, 2^64) or [0, limit) if limit is provided.

    Arguments

    • limit - The upper bound (exclusive) of the random number to be generated (Optional). When limit is 0, the range is [0, 2^64).

    chacha8

    #deprecated("You may use `Rand::chacha8(seed~)` instead of `Rand::new(chacha8(seed~))")
    fn chacha8(seed? : Bytes) -> &Source

    Create a new random number generator with [seed].

    new

    #deprecated("Use `Rand::new()` instead")
    fn new(seed? : Bytes) -> Rand

    Create a new instance.