Ben Chuanlong Du's Blog

It is never too late to learn.

Generating Random Numbers in Rust

Things on this page are fragmentary and immature notes/thoughts of the author. Please read with your own judgement!

Comments

  1. rand::rngs::StdRng (currently, ChaCha block cipher with 12 rounds) is the default recommended RNG which is a trade off among speed, quality and security. While rand::rngs::StdRng is a good default choice as a secure PRNG, it might be too slow for statistical simulations where security is not of a critical concern. rand::rngs::SmallRng (currently, Xoshiro256PlusPlus on 64-bit platforms and Xoshiro128PlusPlus on 32-bit platforms) is a faster alternative for statistical simulations. Note that rand::rngs::SmallRng requires the feature small_rng!

  2. ThreadRng (obtained by calling rand::thread_rng()) is the default recommended RNG for parallel RNGs. It is based on rand::rngs::StdRng and leverages thread-local storage. See Parallel RNGs With Rayon in Rust for more discussions.

  3. Xoshiro256PlusPlus is considered the state-of-the-art (SOTA) PRNG for non-crypographic use cases. Specially, Xoshiro256PlusPlus supports jumping ahead, which means that it can be leveraged to implement a fast and correct parallel PRNG.

  4. getrandom is a small cross-platform library for retrieving random data from system source.

In [2]:
:dep rand = { version = "0.8.5", features = [ "small_rng" ] }
In [3]:
:dep rand_xoshiro = "0.6.0"
In [4]:
use rand::prelude::*;
In [5]:
let mut rng = rand::rngs::StdRng::seed_from_u64(13);
rng.gen::<f64>()
Out[5]:
0.5377847402315655
In [6]:
let mut rng2 = rand::rngs::SmallRng::seed_from_u64(97);
rng2.gen::<f64>()
Out[6]:
0.4337581964978048

Jump Xoshiro256PlusPlus Ahead

In [ ]:
use rand_xoshiro::Xoshiro256PlusPlus;

let mut rng1 = Xoshiro256PlusPlus::seed_from_u64(12397);
let mut rng2 = rng1.clone();
rng2.jump();
let mut rng3 = rng2.clone();
rng3.jump();
Out[ ]:
Xoshiro256PlusPlus { s: [16294208416658607535, 7960286522194355700, 487617019471545679, 17909611376780542444] }

sample

The most generic way to sample a value from a specific distribution is to use the method rng.sample.

Sample from a Discrete Uniform Distribution

Basically you define a discrete uniform distribution and pass it to the method rng.sample.

Question: what is difference among Uniform::new(0u64, 10), Uniform::new(0u32, 10), and Uniform::new(0u16, 10)?

In [19]:
use rand::distributions::Uniform;

rng.sample(Uniform::new(10u32, 15))
Out[19]:
11
In [23]:
use rand::distributions::Uniform;

rng.sample(Uniform::new(10u16, 15))
Out[23]:
12
In [21]:
use rand::distributions::Uniform;

rng.sample(Uniform::new(10u32, 11))
Out[21]:
10

Random Permutation

To generate a random permutation, you have to use the method rand::seq::index::sample . Notice that the returned result is a IndexVec rather than an iterator.

  1. IndexVec is a thin Enum wrapper around Vec.
  2. IndexVec does NOT implement std:ops::Index even though it has a index method.
  3. IndexVec can be converted to a Vec using the method into_vec.
In [6]:
let iv = rand::seq::index::sample(&mut rng, 10, 3);
iv
Out[6]:
U32([1, 9, 0])

IndexVec does not support brackets for accessing elements.

In [7]:
iv[0]

cannot index into a value of type `IndexVec`

You can access elements of an IndexVec using the index method.

In [10]:
iv.index(0)
Out[10]:
1
In [32]:
rand::seq::index::sample(&mut rng, 10, 3).into_vec()
Out[32]:
[7, 0, 2]

Shuffle a Vector

In [8]:
let mut nums: Vec<i32> = (1..100).collect();
nums.shuffle(&mut rng);
In [9]:
println!{"{:?}", nums}
[97, 77, 51, 29, 23, 96, 7, 44, 99, 79, 9, 67, 72, 37, 13, 86, 6, 65, 74, 60, 58, 28, 57, 35, 10, 76, 92, 50, 56, 98, 19, 36, 88, 30, 48, 66, 90, 45, 25, 43, 38, 11, 81, 40, 18, 95, 49, 85, 31, 21, 27, 20, 15, 17, 24, 54, 84, 94, 62, 59, 69, 3, 2, 8, 4, 87, 61, 73, 5, 1, 26, 22, 68, 33, 91, 82, 55, 64, 32, 14, 93, 71, 42, 63, 12, 70, 53, 47, 52, 46, 80, 41, 34, 78, 83, 75, 89, 16, 39]
Out[9]:
()

Parallel RNGs

https://crates.io/crates/rayon supports parallel RNGs. Xoshiro256PlusPlus can be used to construct parallel RNGs as it supports jumping ahead.

In [ ]:

In [ ]:

Comments