# module Random

##
Overview

`Random` provides an interface for random values generation, using a pseudo random number generator (PRNG).

    Random.rand    # => 0.167595
    Random.rand(5) # => 2

The above methods delegate to a `Random` instance.

    r = Random.new
    r.rand      # => 0.0372991
    r.next_bool # => true
    r.next_int  # => 2223112

This module also defines a global method `#rand`, which `Array#sample` and `Array#shuffle` delegates.

    rand     # => 0.293829
    rand(10) # => 8

An instance of each class that includes `Random` is a random number generator with its own state. Usually such RNGs can be initialized with a seed, which defines their initial state. It is guaranteed that after initializing two different instances with the same seed, and then executing the same calls on both of them, you will get the same results. This allows exactly reproducing the same seemingly random events by just keeping the seed.

It is possible to make a custom RNG by including `Random` and implementing `#next_u` to return an unsigned number of a pre-determined type (usually `UInt32`). The numbers generated by your RNG must be uniformly distributed in the whole range of possible values for that type (e.g. `0u32..UInt32::MAX`). This allows all other methods of `Random` to be based on this and still produce uniformly distributed results. Your `Random` class should also have a way to initialize it. For pseudo-random number generators that will usually be an integer seed, but there are no rigid requirements for the initialization.

The default PRNG is `Random::PCG32` which has a good overall statistical distribution (low bias of generated numbers) and is fast for overall usages on different platforms, but isn't cryptographically secure. If a third party has access to some generated numbers, she may deduce incoming numbers, putting your application at risk.

It is recommended to use a secure source, such as `Random::Secure`, `Random::ISAAC` or ChaCha20 for anything that needs security, such as online games, identification tokens, salts, initializing a PRNG, ... These PRNG are slower but cryptographically secure, so a third party can't deduce incoming numbers.

##
Direct including types

- Random::ISAAC
- Random::PCG32

##
Defined in:

big/big_int.cr
random.cr
random/secure.cr

##
Constant Summary

DEFAULT = `PCG32.new`

  DEPRECATED Use `#rand`, `Random.next_int` or `Random::Secure.random_bytes` for example, or create a local instance with `Random.new` instead.

##
Constructors

- .new(seed, sequence = 0_u64)

  Initializes an instance with the given seed and sequence.

- .new

  Initializes an instance seeded from a system source.

- .split : Random

  See `#split`.

##
Class Method Summary

- .next_bool : Bool

  See `#next_bool`.

- .next_int : Int32

  See `#next_int`.

- .rand(x)

  See `#rand(x)`.

- .rand : Float64

  See `#rand`.

##
Instance Method Summary

- #base64(n : Int = 16) : String

  Generates n random bytes that are encoded into base64.

- #hex(n : Int = 16) : String

  Generates a hexadecimal string based on n random bytes.

- #new_seed

  Reseed the generator.

- #next_bool : Bool

  Generates a random `Bool`.

- #next_float : Float64

  See `#rand`.

- #next_int : Int32

  Same as `#rand(Int32::MIN..Int32::MAX)`.

- #next_u

  Generates a random unsigned integer.

- #rand(max : Int) : Int

  Generates a random integer which is greater than or equal to `0` and less than max.

- #rand(max : Float64) : Float64

  Returns a random `Float` which is greater than or equal to `0` and less than max.

- #rand(max : Float32) : Float32

  Returns a random `Float` which is greater than or equal to `0` and less than max.

- #rand(range : Range(Int, Int)) : Int

  Returns a random integer in the given range.

- #rand(range : Range(Float, Float)) : Float

  Returns a random `Float` in the given range.

- #rand(type : StaticArray(Int8, _).class)

  Returns a StaticArray filled with random Int8 values.

- #rand(type : StaticArray(UInt8, _).class)

  Returns a StaticArray filled with random UInt8 values.

- #rand(type : StaticArray(Int16, _).class)

  Returns a StaticArray filled with random Int16 values.

- #rand(type : StaticArray(UInt16, _).class)

  Returns a StaticArray filled with random UInt16 values.

- #rand(type : StaticArray(Int32, _).class)

  Returns a StaticArray filled with random Int32 values.

- #rand(type : StaticArray(UInt32, _).class)

  Returns a StaticArray filled with random UInt32 values.

- #rand(type : StaticArray(Int64, _).class)

  Returns a StaticArray filled with random Int64 values.

- #rand(type : StaticArray(UInt64, _).class)

  Returns a StaticArray filled with random UInt64 values.

- #rand(type : StaticArray(Int128, _).class)

  Returns a StaticArray filled with random Int128 values.

- #rand(type : StaticArray(UInt128, _).class)

  Returns a StaticArray filled with random UInt128 values.

- #rand(type : Int8.class) : Int8

  Returns a random Int8

- #rand(type : UInt8.class) : UInt8

  Returns a random UInt8

- #rand(type : Int16.class) : Int16

  Returns a random Int16

- #rand(type : UInt16.class) : UInt16

  Returns a random UInt16

- #rand(type : Int32.class) : Int32

  Returns a random Int32

- #rand(type : UInt32.class) : UInt32

  Returns a random UInt32

- #rand(type : Int64.class) : Int64

  Returns a random Int64

- #rand(type : UInt64.class) : UInt64

  Returns a random UInt64

- #rand(type : Int128.class) : Int128

  Returns a random Int128

- #rand(type : UInt128.class) : UInt128

  Returns a random UInt128

- #rand : Float64

  Generates a random `Float64` between `0` and `1`.

- #random_bytes(n : Int = 16) : Bytes

  Generates a slice filled with n random bytes.

- #random_bytes(buf : Bytes) : Nil

  Fills a given slice with random bytes.

- #split : self

  Splits the current instance into two seemingly independent instances that will return distinct sequences of random numbers.

- #split_internal(other : self) : Nil

  The internal implementation for `#split` where self is the original instance and other the duplicated instance to be returned.

- #urlsafe_base64(n : Int = 16, padding = false) : String

  Generates n random bytes that are encoded as a URL-safe base64 string.

##
Constructor Detail

def self.new(seed, sequence = 0_u64) #

Initializes an instance with the given seed and sequence.

def self.new #

Initializes an instance seeded from a system source.

def self.split : Random #

See `#split`.

##
Class Method Detail

def self.next_bool : Bool #

See `#next_bool`.

def self.next_int : Int32 #

See `#next_int`.

def self.rand(x) #

See `#rand(x)`.

def self.rand : Float64 #

See `#rand`.

##
Instance Method Detail

def base64(n : Int = 16) : String #

Generates n random bytes that are encoded into base64.

The parameter n specifies the length, in bytes, of the random number to be generated. The length of the result string is about 4/3 of n due to the base64 encoding. The result receives a padding consisting of `=` characters to fill up the string size to a multiple of 4.

Check `Base64#strict_encode` for details.

    Random::Secure.base64(4) # => "fK1eYg=="

It is recommended to use the secure `Random::Secure` as a source or another cryptographically quality PRNG such as `Random::ISAAC` or ChaCha20.

def hex(n : Int = 16) : String #

Generates a hexadecimal string based on n random bytes.

The bytes are encoded into a string of two-digit hexadecimal number (00-ff) per byte.

    Random::Secure.hex    # => "05f100a1123f6bdbb427698ab664ff5f"
    Random::Secure.hex(1) # => "1a"

It is recommended to use the secure `Random::Secure` as a source or another cryptographically quality PRNG such as `Random::ISAAC` or ChaCha20.

def new_seed #

Reseed the generator.

def next_bool : Bool #

Generates a random `Bool`.

    Random.new.next_bool # => true

def next_float : Float64 #

See `#rand`.

def next_int : Int32 #

Same as `#rand(Int32::MIN..Int32::MAX)`.

abstract def next_u #

Generates a random unsigned integer.

The integers must be uniformly distributed between `0` and the maximal value for the chosen type.

def rand(max : Int) : Int #

Generates a random integer which is greater than or equal to `0` and less than max.

The return type always matches the supplied argument.

    Random.new.rand(10)   # => 5
    Random.new.rand(5000) # => 2243

def rand(max : Float64) : Float64 #

Returns a random `Float` which is greater than or equal to `0` and less than max.

    Random.new.rand(3.5)    # => 2.88938
    Random.new.rand(10.725) # => 7.70147

def rand(max : Float32) : Float32 #

Returns a random `Float` which is greater than or equal to `0` and less than max.

    Random.new.rand(3.5)    # => 2.88938
    Random.new.rand(10.725) # => 7.70147

def rand(range : Range(Int, Int)) : Int #

Returns a random integer in the given range.

The return type always matches the supplied argument.

    Random.new.rand(10..20)                 # => 14
    Random.new.rand(Int64::MIN..Int64::MAX) # => -5297435808626736140

def rand(range : Range(Float, Float)) : Float #

Returns a random `Float` in the given range.

    Random.new.rand(6.2..21.768) # => 15.2989

def rand(type : StaticArray(Int8, _).class) #

Returns a StaticArray filled with random Int8 values.

    rand(StaticArray(Int8, 4)) # => StaticArray[20, -66, 89, 19]

def rand(type : StaticArray(UInt8, _).class) #

Returns a StaticArray filled with random UInt8 values.

    rand(StaticArray(UInt8, 4)) # => StaticArray[186, 221, 127, 245]

def rand(type : StaticArray(Int16, _).class) #

Returns a StaticArray filled with random Int16 values.

    rand(StaticArray(Int16, 4)) # => StaticArray[-32554, 32169, -20152, -7686]

def rand(type : StaticArray(UInt16, _).class) #

Returns a StaticArray filled with random UInt16 values.

    rand(StaticArray(UInt16, 4)) # => StaticArray[39546, 44091, 2874, 17348]

def rand(type : StaticArray(Int32, _).class) #

Returns a StaticArray filled with random Int32 values.

    rand(StaticArray(Int32, 4)) # => StaticArray[1870830079, -1043532158, -867180637, -1216773590]

def rand(type : StaticArray(UInt32, _).class) #

Returns a StaticArray filled with random UInt32 values.

    rand(StaticArray(UInt32, 4)) # => StaticArray[3147957137, 4245108745, 2207809043, 3184391838]

def rand(type : StaticArray(Int64, _).class) #

Returns a StaticArray filled with random Int64 values.

    rand(StaticArray(Int64, 4)) # => StaticArray[4438449217673515190, 8514493061600538358, -4874671083204037318, -7825896160729246667]

def rand(type : StaticArray(UInt64, _).class) #

Returns a StaticArray filled with random UInt64 values.

    rand(StaticArray(UInt64, 4)) # => StaticArray[15004487597684511003, 12027825265648206103, 11303949506191212698, 6228566501671148658]

def rand(type : StaticArray(Int128, _).class) #

Returns a StaticArray filled with random Int128 values.

    rand(StaticArray(Int128, 4)) # => StaticArray[-33248638598154624979861619415313153263, 7715345987200799268985566794637461715, 51883986405785085023723116953594906714, -63505201678563022521901409748929046368]

def rand(type : StaticArray(UInt128, _).class) #

Returns a StaticArray filled with random UInt128 values.

    rand(StaticArray(UInt128, 4)) # => StaticArray[209016375821699277802308597707088869733, 168739091726124084850659068882871627438, 293712757766410232411790495845165436283, 15480005665598870938163293877660434201]

def rand(type : Int8.class) : Int8 #

Returns a random Int8

    rand(Int8) # => 20

def rand(type : UInt8.class) : UInt8 #

Returns a random UInt8

    rand(UInt8) # => 186

def rand(type : Int16.class) : Int16 #

Returns a random Int16

    rand(Int16) # => -32554

def rand(type : UInt16.class) : UInt16 #

Returns a random UInt16

    rand(UInt16) # => 39546

def rand(type : Int32.class) : Int32 #

Returns a random Int32

    rand(Int32) # => 1870830079

def rand(type : UInt32.class) : UInt32 #

Returns a random UInt32

    rand(UInt32) # => 3147957137

def rand(type : Int64.class) : Int64 #

Returns a random Int64

    rand(Int64) # => 4438449217673515190

def rand(type : UInt64.class) : UInt64 #

Returns a random UInt64

    rand(UInt64) # => 15004487597684511003

def rand(type : Int128.class) : Int128 #

Returns a random Int128

    rand(Int128) # => -33248638598154624979861619415313153263

def rand(type : UInt128.class) : UInt128 #

Returns a random UInt128

    rand(UInt128) # => 209016375821699277802308597707088869733

def rand : Float64 #

Generates a random `Float64` between `0` and `1`.

    r = Random.new
    r.rand # => 0.167595
    r.rand # => 0.0372991

def random_bytes(n : Int = 16) : Bytes #

Generates a slice filled with n random bytes.

    Random.new.random_bytes    # => [145, 255, 191, 133, 132, 139, 53, 136, 93, 238, 2, 37, 138, 244, 3, 216]
    Random.new.random_bytes(4) # => [217, 118, 38, 196]

def random_bytes(buf : Bytes) : Nil #

Fills a given slice with random bytes.

    slice = Bytes.new(4) # => [0, 0, 0, 0]
    Random.new.random_bytes(slice)
    slice # => [217, 118, 38, 196]

def split : self #

Splits the current instance into two seemingly independent instances that will return distinct sequences of random numbers. Returns a new instance.

    random = Random.new
    split1 = random.split
    split2 = random.split

    Array.new(5) { random.rand(99) } # => [79, 42, 54, 17, 52]
    Array.new(5) { split1.rand(99) } # => [90, 37, 15, 74, 61]
    Array.new(5) { split2.rand(99) } # => [6, 87, 5, 73, 71]

def split_internal(other : self) : Nil #

The internal implementation for `#split` where self is the original instance and other the duplicated instance to be returned.

The default `Random` implementation in stdlib is splittable, but not every PRNG algorithm is splittable, so the method raises a `NotImplementedError` exception by default.

def urlsafe_base64(n : Int = 16, padding = false) : String #

Generates n random bytes that are encoded as a URL-safe base64 string.

The parameter n specifies the length, in bytes, of the random number to be generated. The length of the result string is about 4/3 of n due to the base64 encoding. If padding is `true`, the result receives a padding consisting of `=` characters to fill up the string size to a multiple of 4.

Check `Base64#urlsafe_encode` for details.

    Random::Secure.urlsafe_base64                    # => "MAD2bw8QaBdvITCveBNCrw"
    Random::Secure.urlsafe_base64(8, padding: true)  # => "vvP1kcs841I="
    Random::Secure.urlsafe_base64(16, padding: true) # => "og2aJrELDZWSdJfVGkxNKw=="

It is recommended to use the secure `Random::Secure` as a source or another cryptographically quality PRNG such as `Random::ISAAC` or ChaCha20.