我想生成一个范围(n到m,例如100到150)的随机数,但我希望结果不是纯随机的,而是基于正态分布。
我的意思是,一般来说,我希望数字“聚集”在125左右。
我发现这个随机数字包似乎有很多我需要的东西:http://codeproject.com/KB/recipes/Random.aspx
它支持各种随机生成器(包括mersiene twister),可以将生成器应用于发行版。
但是我很困惑,如果我使用正态分布生成器,随机数大约从-6到+8(显然真正的范围是float.min到float.max)。
如何缩放到我要求的范围?
答案 0 :(得分:26)
标准正态分布的平均值为0,标准差为1;如果您想使用平均值m
和偏差s
进行分配,只需乘以s
然后再添加m
即可。由于正态分布在理论上是无限的,因此您的范围不能有硬限制,例如: (100至150)没有明确拒绝不属于它的数字,但如果有适当的偏差选择,您可以放心(例如)99%的数字将在该范围内。
大约99.7%的人口在+/- 3标准差内,所以如果你选择你的大约(25/3)
,它应该运作良好。
所以你需要这样的东西:(normal * 8.333) + 125
答案 1 :(得分:14)
为了感兴趣,从统一的RNG生成正态分布的随机数非常简单(尽管必须成对完成):
Random rng = new Random();
double r = Math.Sqrt(-2 * Math.Log(rng.NextDouble()));
double θ = 2 * Math.Pi * rng.NextDouble();
double x = r * Math.Cos(θ);
double y = r * Math.Sin(θ);
x
和y
现在包含两个独立的,正态分布的随机数,均值为0和方差1.您可以根据需要进行缩放和翻译,以获得所需的范围(如同间隔解释的那样)。
<强>解释强>
此方法称为Box–Muller transform。它使用二维单位Gaussian的属性,密度值本身p = exp(-r^2/2)
均匀分布在0
和1
之间(为简单起见,删除了归一化常数)。
由于您可以使用统一的RNG轻松生成此类值,因此最终得到半径为r = sqrt(-2 * log(p))
的圆形轮廓。然后,您可以在0
和2*pi
之间生成第二个均匀随机变量,为您提供一个角度θ
,用于定义圆形轮廓上的唯一点。最后,您可以通过将极坐标(r, θ)
转换回笛卡尔坐标(x, y)
来生成两个i.i.d.正态随机变量。
这个属性 - p
均匀分布 - 不适用于其他维度,这就是为什么你必须一次只生成两个正常变量。
答案 2 :(得分:4)
tzaman的答案是正确的,但是当你使用你链接的库时,有一种比自己执行计算更简单的方法:NormalDistribution
对象具有可写属性Mu
(意思是均值)和{{1 (标准偏差)。因此,按照tzaman的数字,将Sigma
设置为125,将Mu
设置为8.333。
答案 3 :(得分:2)
这可能过于简单,无法满足您的需求,但快速而且快速。通过向中心加权的分布获得随机数的便宜方法是简单地添加2个(或更多)随机数。
想一想你滚动两个6面骰子并添加它们。总和通常是7,然后是6和8,然后是5和9等,而且很少只有2或12。
答案 4 :(得分:0)
这是另一个不需要计算Sin / Cos的算法,也不需要知道Pi。不要问我理论背景。我已经在某个地方找到了它,这是我以后一直在使用的。我怀疑这是@Will Vousden提到的同一Box-Muller变换的某种规范化。它也会成对产生结果。
示例是VBscript;很容易转换成任何其他语言。
Sub calcRandomGauss (byref y1, byref y2)
Dim x1, x2, w
Do
x1 = 2.0 * Rnd() - 1.0
x2 = 2.0 * Rnd() - 1.0
w = x1 * x1 + x2 * x2
Loop While w >= 1.0 Or w = 0 'edited this line, thanks Richard
w = Sqr((-2.0 * Log(w)) / w )
y1 = x1 * w
y2 = x2 * w
End Sub
答案 5 :(得分:0)
此问题的另一种方法是使用 beta分布(与正态分布不同,它具有硬范围)并且涉及选择适当的参数,使分布具有给定的均值和标准差(方差的平方根)。请参阅this question。