I am trying to generate multiple random u32 integers in a very narrow range. My maximum and minimum both vary between 1 and 6 really. I would like to bias the generator towards the middle of the range.
I have tried using the Normal
distribution from the rand_distr
crate, but it seems to be for floats and unbounded beyond probability, i.e. I want values between 2 and 5 but I can potentially get a result like 0.81 or 6.92 even if they are rather rare. I wasn't able to find an integer version of the Normal
distribution in the documentation. I am assuming it does not exist.
I would also like this to be efficient so I have a feeling the normal distribution for floats would not be very performant. I've also noticed a distribution called weighted indexes but this would require manual computation of weights with every iteration.
Perhaps the regular get_range
for integer values can be biased towards the mean arithmetically somehow after the generator runs. Does anyone have any interesting solutions for this?
If you want to have a biased random distribution from a sample of values, you can use the rand
crate's rand::distributions::weighted::WeightedIndex
to have fine grain control over your biasness by defining weights of each item in the sample.
use rand::prelude::*;
use rand::distributions::WeightedIndex;
fn main(){
let mut rng = thread_rng();
//item value and it's weight increasing till middle and then decreasing till end
let sample_item = [('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 3), ('f', 2), ('g', 1)];
let weight_dist = WeightedIndex::new(sample_item.iter().map(|(_, weight)| weight)).unwrap();
let mut pool = vec![];
for _ in 1..100{
let item = sample_item[weight_dist.sample(&mut rng)];
pool.push(item.0);
}
println!("{:?}", pool.iter().filter(|x| **x == 'a').count());
println!("{:?}", pool.iter().filter(|x| **x == 'b').count());
println!("{:?}", pool.iter().filter(|x| **x == 'c').count());
println!("{:?}", pool.iter().filter(|x| **x == 'd').count());
println!("{:?}", pool.iter().filter(|x| **x == 'e').count());
println!("{:?}", pool.iter().filter(|x| **x == 'f').count());
}
You can try out the code here