Random Number

Generate Random Number

Computers generate random numbers using two main methods:

  1. True Random Number Generators (TRNGs) that rely on inherently random physical and unpredictable processes such as radioactive decay, mouse movements, fan noise, etc and convert them into random number.
  2. Pseudo-Random Number Generators (PRNGs): uses deterministic algorithm that start with an initial seed value and quickly produce a deterministic sequence of numbers that appear random. PRNGs are the ones we use.

Crate rand

use rand::Rng;

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

    if rand::random() {    // generate a boolean
        println!("char: {}", rand::random::<char()>); // generate a random unicode char
    }

    let n1: u8 = rng.gen();      // generate a u8 int
    let n2: f64 = rng.gen();    // generate a f64 between 0-1
    println!("Random u8: {}", n1);
    println!("Random f64: {}", n2);
    println!("Random u32: {}", rng.gen::<u32>());
    println!("Random i32: {}", rng.gen::<i32>());
    println!("Random float: {}", rng.gen::<f64>());

    // range
    println!("Integer: {}", rng.gen_range(0..10)); // [0,10)
    println!("Float: {}", rng.gen_range(0.0..10.0));

    let mut nums: Vec<i32> = (1..100).collect();
    nums.shuffle(&mut rng);
}

By default, rand crate have uniform distribution, which we can aso generate as follows:


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;
        }
    }
}

We can generate Random Number with other distributions from rand_distr


use rand_distr::{Distribution, Normal, NormalError};
use rand::thread_rng;

fn main() -> Result<(), NormalError> {

    let mut rng = thread_rng();
    let normal = Normal::new(1.0, 2.0)?;  // (μ,σ^2) // other constructs are also available
    let v = normal.sample(&mut rng);
    println!("{} is from a N(1, 4) distribution", v);
    Ok(())
}

Generate random set of alphanumeric ASCII characters for example to create a password

use rand::{thread_rng, Rng};
use rand::distributions::Alphanumeric;

fn main() {
    let rand_string: String = thread_rng()
        .sample_iter(&Alphanumeric)
        .take(30)
        .map(char::from)
        .collect();

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

To include user defined bytestring in the password

fn main() {
    use rand::Rng;
    const CHARSET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
                            abcdefghijklmnopqrstuvwxyz\
                            0123456789)(*&^%$#@!~";
    const PASSWORD_LEN: usize = 30;
    let mut rng = rand::thread_rng();

    let password: String = (0..PASSWORD_LEN)
        .map(|_| {
            let idx = rng.gen_range(0..CHARSET.len());
            CHARSET[idx] as char
        })
        .collect();

    println!("{:?}", password);
}

Custom Random Number Generator

use rand::Rng;
use rand::distributions::{Distribution, Standard};

#[derive(Debug)]
struct Point {
    x: i32,
    y: i32,
}

impl Distribution<Point> for Standard {  //implement Distribution trait on the new type Point for Standard (generic RV dist)
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Point {
        let (rand_x, rand_y) = rng.gen();
        Point {
            x: rand_x,
            y: rand_y,
        }
    }
}

fn main() {
    let mut rng = rand::thread_rng();
    let rand_tuple = rng.gen::<(i16, bool, f64)>();  // random tuple of our choice
    let rand_point: Point = rng.gen();
    println!("Random tuple: {:?}", rand_tuple);
    println!("Random Point: {:?}", rand_point);
}