Rand is a Rust library for random number generation.
Rand provides utilities to generate random numbers, to convert them to useful types and distributions, and some randomness-related algorithms.
The core random number generation traits of Rand live in the rand_core crate but are also exposed here; RNG implementations should prefer to use rand_core
while most other users should depend on rand
.
Step 1: Install it
Install it by declaring it as a dependency in your Cargo.toml
;
[dependencies]
rand = "0.7"
Step 2: Write Code
Start by importing commonly used items from the prelude:
use rand::prelude::*;
Create the main function:
fn main() {
We can use random()
immediately. It can produce values of many common types:
let x: u8 = random();
println!("{}", x);
if random() { // generates a boolean
println!("Heads!");
}
If we want to be a bit more explicit (and a little more efficient) we can make a handle to the thread-local generator:
let mut rng = thread_rng();
if rng.gen() { // random bool
let x: f64 = rng.gen(); // random number in range [0, 1)
let y = rng.gen_range(-10.0..10.0);
println!("x is: {}", x);
println!("y is: {}", y);
}
println!("Die roll: {}", rng.gen_range(1..=6));
println!("Number from 0 to 9: {}", rng.gen_range(0..10));
Sometimes it's useful to use distributions directly:
let distr = rand::distributions::Uniform::new_inclusive(1, 100);
let mut nums = [0i32; 3];
for x in &mut nums {
*x = rng.sample(distr);
}
println!("Some numbers: {:?}", nums);
We can also interact with iterators and slices:
let arrows_iter = "➡⬈⬆⬉⬅⬋⬇⬊".chars();
println!("Lets go in this direction: {}", arrows_iter.choose(&mut rng).unwrap());
let mut nums = [1, 2, 3, 4, 5];
nums.shuffle(&mut rng);
println!("I shuffled my {:?}", nums);
}
Here is the full code:
extern crate rand;
use rand::prelude::*;
fn main() {
let x: u8 = random();
println!("{}", x);
if random() { // generates a boolean
println!("Heads!");
}
let mut rng = thread_rng();
if rng.gen() { // random bool
let x: f64 = rng.gen(); // random number in range [0, 1)
let y = rng.gen_range(-10.0..10.0);
println!("x is: {}", x);
println!("y is: {}", y);
}
println!("Die roll: {}", rng.gen_range(1..=6));
println!("Number from 0 to 9: {}", rng.gen_range(0..10));
let distr = rand::distributions::Uniform::new_inclusive(1, 100);
let mut nums = [0i32; 3];
for x in &mut nums {
*x = rng.sample(distr);
}
println!("Some numbers: {:?}", nums);
let arrows_iter = "➡⬈⬆⬉⬅⬋⬇⬊".chars();
println!("Lets go in this direction: {}", arrows_iter.choose(&mut rng).unwrap());
let mut nums = [1, 2, 3, 4, 5];
nums.shuffle(&mut rng);
println!("I shuffled my {:?}", nums);
}
If your run it you will get the following:
7
x is: 0.517167238666765
y is: -6.704933411474037
Die roll: 6
Number from 0 to 9: 8
Some numbers: [92, 64, 43]
Lets go in this direction: ⬇
I shuffled my [1, 4, 2, 5, 3]
Example 2: Generate Random Numbers
You can generate random numbers using the rand::Rng
obtained via rand::thread_rng
Each thread will have an initialized generator. Integers are uniformly distributed over the range of the type, and floating point numbers are uniformly distributed from 0 up to but not including 1.
use rand::Rng;
fn main() {
let mut rng = rand::thread_rng();
let n1: u8 = rng.gen();
let n2: u16 = rng.gen();
println!("Random u8: {}", n1);
println!("Random u16: {}", n2);
println!("Random u32: {}", rng.gen::<u32>());
println!("Random i32: {}", rng.gen::<i32>());
println!("Random float: {}", rng.gen::<f64>());
}
If you run the code you will get:
Random u8: 152
Random u16: 18699
Random u32: 315736307
Random i32: 499439293
Random float: 0.6544549188378622
Example 3: Generate Random Numbers within a Range
You can use the Rng::gen_range
to generate random numbers within half-open [0, 10) range (not including 10).
Here's an example:
use rand::Rng;
fn main() {
let mut rng = rand::thread_rng();
println!("Integer: {}", rng.gen_range(0..10));
println!("Float: {}", rng.gen_range(0.0..10.0));
}
If you run it you will get:
Integer: 6
Float: 1.497327366848702
Example 4: Generate Numbers with Uniform Distribution
Here's an example:
use rand::distributions::{Distribution, Uniform};
fn main() {
let mut rng = rand::thread_rng();
let die = Uniform::from(1..7);
loop {
let throw = die.sample(&mut rng);
println!("Roll the die: {}", throw);
if throw == 6 {
break;
}
}
}
If you run it you will get:
Roll the die: 5
Roll the die: 3
Roll the die: 3
Roll the die: 4
Roll the die: 1
Roll the die: 2
Roll the die: 3
Roll the die: 1
Roll the die: 6
Example 5
monte-carlo.rs
use rand::distributions::{Distribution, Uniform};
fn main() {
let range = Uniform::new(-1.0f64, 1.0);
let mut rng = rand::thread_rng();
let total = 1_000_000;
let mut in_circle = 0;
for _ in 0..total {
let a = range.sample(&mut rng);
let b = range.sample(&mut rng);
if a * a + b * b <= 1.0 {
in_circle += 1;
}
}
// prints something close to 3.14159...
println!(
"π is approximately {}",
4. * (in_circle as f64) / (total as f64)
);
}
Run it and you will get the following;
π is approximately 3.140444
Example 6
monty-hall.rs
use rand::distributions::{Distribution, Uniform};
use rand::Rng;
struct SimulationResult {
win: bool,
switch: bool,
}
// Run a single simulation of the Monty Hall problem.
fn simulate<R: Rng>(random_door: &Uniform<u32>, rng: &mut R) -> SimulationResult {
let car = random_door.sample(rng);
// This is our initial choice
let mut choice = random_door.sample(rng);
// The game host opens a door
let open = game_host_open(car, choice, rng);
// Shall we switch?
let switch = rng.gen();
if switch {
choice = switch_door(choice, open);
}
SimulationResult {
win: choice == car,
switch,
}
}
// Returns the door the game host opens given our choice and knowledge of
// where the car is. The game host will never open the door with the car.
fn game_host_open<R: Rng>(car: u32, choice: u32, rng: &mut R) -> u32 {
use rand::seq::SliceRandom;
*free_doors(&[car, choice]).choose(rng).unwrap()
}
// Returns the door we switch to, given our current choice and
// the open door. There will only be one valid door.
fn switch_door(choice: u32, open: u32) -> u32 {
free_doors(&[choice, open])[0]
}
fn free_doors(blocked: &[u32]) -> Vec<u32> {
(0..3).filter(|x| !blocked.contains(x)).collect()
}
fn main() {
// The estimation will be more accurate with more simulations
let num_simulations = 10000;
let mut rng = rand::thread_rng();
let random_door = Uniform::new(0u32, 3);
let (mut switch_wins, mut switch_losses) = (0, 0);
let (mut keep_wins, mut keep_losses) = (0, 0);
println!("Running {} simulations...", num_simulations);
for _ in 0..num_simulations {
let result = simulate(&random_door, &mut rng);
match (result.win, result.switch) {
(true, true) => switch_wins += 1,
(true, false) => keep_wins += 1,
(false, true) => switch_losses += 1,
(false, false) => keep_losses += 1,
}
}
let total_switches = switch_wins + switch_losses;
let total_keeps = keep_wins + keep_losses;
println!(
"Switched door {} times with {} wins and {} losses",
total_switches, switch_wins, switch_losses
);
println!(
"Kept our choice {} times with {} wins and {} losses",
total_keeps, keep_wins, keep_losses
);
// With a large number of simulations, the values should converge to
// 0.667 and 0.333 respectively.
println!(
"Estimated chance to win if we switch: {}",
switch_wins as f32 / total_switches as f32
);
println!(
"Estimated chance to win if we don't: {}",
keep_wins as f32 / total_keeps as f32
);
}
Run it and you will get:
Running 10000 simulations...
Switched door 5056 times with 3354 wins and 1702 losses
Kept our choice 4944 times with 1637 wins and 3307 losses
Estimated chance to win if we switch: 0.66337025
Estimated chance to win if we don't: 0.33110842
Example 7
main.rs
use rand::thread_rng;
use rand::Rng;
fn main() {
// let i : i32 = rand::random();
// println!("The random i32 is {} ", i);
// let x: u8 = rand::random();
// println!("The random u8 is {}", x);
// let x: f64 = rand::random();
// println!("The random f64 is {}", x);
// let x:bool = rand::random();
// println!("The random bool {}", x);
//What about generating a random number within a range?
//For that, you need to create a random number generator and call its gen_range() function.
// let mut rng = thread_rng();
// let y: f64 = rng.gen_range(-10.0, 10.0);
// println!("Number from -10. to 10.: {}", y);
// println!("Number from 0 to 9: {}", rng.gen_range(0, 10));
// for i in 1..10 {
// println!("Random number #{}: {}", i, rng.gen_range(0, 100));
// }
// let mut arr = [0i32; 9];
// thread_rng().try_fill(&mut arr[..]).unwrap();
// println!("Random number array {:?}", arr);
//Another neat feature of the generator is that
//it can generate random numbers from a probability distribution.
let mut rng = thread_rng();
let distr = rand::distributions::Uniform::new_inclusive(1, 100);
let mut nums = [0i32; 3];
for x in &mut nums {
*x = rng.sample(distr);
}
println!("Some numbers: {:?} ", nums);
}
Run and you will get:
Some numbers: [47, 15, 71]