Chris Jefferson
Chris Jefferson

Reputation: 7157

How to generate a random Rust integer in a range without introducing bias?

How you I generate a random dice roll in Rust?

I know I can use rand::random, but that requires I want to generate a value of an integer type. Using rand::random<u8>() % 6 introduces a bias.

Upvotes: 5

Views: 5869

Answers (2)

Shepmaster
Shepmaster

Reputation: 430673

Use Rng::gen_range for a one-off value:

use rand::{self, Rng}; // 0.8.0

fn main() {
    let mut rng = rand::thread_rng();

    let die = rng.gen_range(1..=6);

    println!("The die was: {}", die);
}

Under the hood, this creates a Uniform struct. Create this struct yourself if you will be getting multiple random numbers:

use rand::{
    self,
    distributions::{Distribution, Uniform},
}; // 0.8.0

fn main() {
    let mut rng = rand::thread_rng();
    let die_range = Uniform::new_inclusive(1, 6);

    let die = die_range.sample(&mut rng);

    println!("{}", die);
}

Uniform does some precomputation to figure out how to map the complete range of random values to your desired range without introducing bias. It translates and resizes your original range to most closely match the range of the random number generator, discards any random numbers that fall outside this new range, then resizes and translates back to the original range.

See also:

Upvotes: 9

lynks
lynks

Reputation: 5689

You're correct that a bias is introduced; whenever you want to map from set A to set B where the cardinality of set B is not a factor or multiple of set A, you will have bias.

In your case, 42*6=252. So you can just throw away any u8 values of 252 or greater (and call random again).

Your output can then be safely mapped with the modulus operator. Finally add 1 to achieve the standard [1,6] dice output.

It might seem unclean to call random again but there is no way of mapping a set of 256 values to a set of 6 without introducing bias.

Edit: looks like the rand crate has something which takes bias into account: https://docs.rs/rand/latest/rand/distributions/uniform/struct.Uniform.html

Upvotes: 3

Related Questions