在偏向中间的范围内生成随机无符号整数
Generating random unsigned integers within a range biased toward the middle
我试图在一个非常窄的范围内生成多个随机 u32 整数。我的最大值和最小值都在 1 到 6 之间变化。我想将生成器偏向范围的中间。
我有 tried using the Normal
distribution from the rand_distr
crate,但它似乎是针对浮点数和无限概率的,即我想要 2 到 5 之间的值,但我可能会得到像 0.81 或 6.92 这样的结果,即使它们相当罕见.我无法在文档中找到 Normal
发行版的整数版本。我假设它不存在。
我也希望它是高效的,所以我感觉浮点数的正态分布不会非常高效。我还注意到一个称为加权索引的分布,但这需要在每次迭代时手动计算权重。
也许在生成器运行后,整数值的常规 get_range
可以以某种方式在算术上偏向平均值。有人对此有任何有趣的解决方案吗?
一个粗略的解决方案:从区间内的均匀分布中取 2 个数字并使用平均值。
它会给出这样的分布:_/\_
为了更精细的控制,您需要一些逐步插值。
如果您希望从值样本中获得有偏差的随机分布,您可以使用 rand
crate's rand::distributions::weighted::WeightedIndex
通过定义样本中每个项目的权重来精细控制偏差。
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());
}
您可以试试代码here
我试图在一个非常窄的范围内生成多个随机 u32 整数。我的最大值和最小值都在 1 到 6 之间变化。我想将生成器偏向范围的中间。
我有 tried using the Normal
distribution from the rand_distr
crate,但它似乎是针对浮点数和无限概率的,即我想要 2 到 5 之间的值,但我可能会得到像 0.81 或 6.92 这样的结果,即使它们相当罕见.我无法在文档中找到 Normal
发行版的整数版本。我假设它不存在。
我也希望它是高效的,所以我感觉浮点数的正态分布不会非常高效。我还注意到一个称为加权索引的分布,但这需要在每次迭代时手动计算权重。
也许在生成器运行后,整数值的常规 get_range
可以以某种方式在算术上偏向平均值。有人对此有任何有趣的解决方案吗?
一个粗略的解决方案:从区间内的均匀分布中取 2 个数字并使用平均值。
它会给出这样的分布:_/\_
为了更精细的控制,您需要一些逐步插值。
如果您希望从值样本中获得有偏差的随机分布,您可以使用 rand
crate's rand::distributions::weighted::WeightedIndex
通过定义样本中每个项目的权重来精细控制偏差。
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());
}
您可以试试代码here