需要帮助从分布中生成离散的随机数

时间:2009-07-28 23:38:05

标签: objective-c math random numbers distribution

我搜索了网站,但没找到我到底想要的东西......我想从正态分布中生成一个离散的随机数。

例如,如果我的范围从最小值4到最大值10,平均值为7.我需要返回一个代码或函数调用(目标C首选),返回该范围内的数字。当然,由于正态分布,更多的数字将以7的平均值为中心。

作为第二个例子,钟形曲线/分布是否可以向另一端倾斜?假设我需要生成一个最小值为4且最大值为10的随机数,并且我希望返回的大多数数字以数字8为中心,基于倾斜的钟形曲线自然下降。

非常感谢任何帮助......

安东尼

5 个答案:

答案 0 :(得分:4)

你需要什么?你可以用掷骰子玩家的方式吗?

生成两个随机整数,范围为2到5(当然也包括在内)并将它们加在一起。或者将硬币(0,1)翻转六次并在结果中加4。

  

Summing multiple dice produces a normal distribution (a "bell curve"), while eliminating high or low throws can be used to skew the distribution in various ways.

关键是你要使用离散数字(我希望你的意思是整数)。多个骰子抛出着名的产生正常分布。事实上,我认为这就是我们在学校首次引入高斯曲线的方式。


当然投掷越多,你越接近钟形曲线。滚动单个模具会产生扁平线。滚动两个骰子只会创建一个上升和下降的斜坡,并不是非常靠近钟。六枚硬币翻转让你更接近。

所以考虑一下......

如果我正确理解你的问题,你只有七种可能的结果 - 整数(4,5,6,7,8,9,10)。您可以设置七个概率的数组来近似您喜欢的任何分布。

答案 1 :(得分:1)

其端点不描述正态分布。通常用它的平均值(你给出的是7)和它的标准偏差来描述。这一点的一个重要特征是可以从这个分布中得到一个远远超出预期范围的值,尽管这种情况很少见,你从平均值得到的距离越远。

从分布中获取值的常用方法是从统一分布生成随机值,这很容易用例如rand()完成,然后将其用作{的参数{3}}将概率映射到上限。对于标准分发,此功能是

F(x) = 0.5 - 0.5*erf( (x-μ)/(σ * sqrt(2.0)))

其中erf()cumulative distribution function,,可由泰勒系列描述:

  

erf(z)= 2.0 / sqrt(2.0)*Σ n = 0 ((-1) n z 2n + 1 )/(n!(2n + 1))

我会把它作为一个练习,把它翻译成C.

如果您不想参与练习,您可以考虑使用error function,其中包括许多其他功能中的一种技术,可以在许多常见分布中生成随机数,其中包括高斯分布(提示)是一个。

显然,所有这些函数都返回浮点值。您将不得不使用一些舍入策略来转换为离散值。一个有用的(但天真的)方法是简单地向下转换为整数。

答案 2 :(得分:1)

许多框架和库都内置了这个。

此外,就像TokenMacGuy所说的那样,正态分布不是由 interval 定义的,而是由两个参数定义:Mean μ和标准偏差σ。使用这两个参数,您可以将某个quantile的分布限制在一定的时间间隔内,这样95%的所有点都会落入间隔。但是将它完全重新排除到除(-∞,∞)以外的任何区间都是不可能的。

有几种方法可以从均匀随机值生成正态分布值(这是大多数随机数或伪随机数生成器生成的:

  • Box-Muller transform可能是最简单的,但计算速度不是很快。根据您需要的数字数量,它应该足够,但写起来非常容易。

  • 另一种选择是Marsaglia的Polar method,通常更快 1

  • 第三种方法是Ziggurat algorithm,它的计算速度要快得多,但编程要复杂得多。在真正使用很多随机数的应用程序中,它可能是最好的选择。

作为一般性建议:如果您有权访问为您生成正态分布随机数的库,请不要自己编写。


为了扭曲您的分布,我只使用常规正态分布,在曲线的一侧适当选择μσ,然后确定您的哪一侧想要意味着一个点落下,适当地拉伸它以适合你想要的分布。


为了只生成整数,我建议你在随机数恰好落在你想要的区间内时向最接近的整数舍入,如果没有,则拒绝它(然后绘制一个新的随机数)。通过这种方式,您不会人为地扭曲分布(例如,如果您将值分别设置为4或10,则会这样做。)


1 在使用故意坏的随机数生成器进行测试(是的,比RANDU差)我注意到极性方法导致无限循环,拒绝每个样本。但是,随机数字不会达到通常的统计预期。

答案 3 :(得分:1)

是的,有复杂的数学解决方案,但对于“简单但实用”,我会选择Nosredna的评论。对于简单的Java解决方案:

Random random=new Random();
public int bell7()
{
  int n=4;
  for (int x=0;x<6;++x)
    n+=random.nextInt(2);
  return n;
}

如果您不是Java人员,则Random.nextInt(n)返回0到n-1之间的随机整数。我认为其余的应该与您在任何编程语言中看到的类似。

如果范围很大,那么我会使用更大的数字代替nextInt(2),因此循环中的迭代次数会减少,具体取决于调用频率和性能要求。

答案 4 :(得分:1)

Dan Dyer和Jay完全正确。你真正想要的是二项分布,而不是正态分布。二项分布的形状看起来很像正态分布,但它是离散的和有界的,而正态分布是连续的和无界的。

Jay的代码生成二项分布,每次试验有6次试验,成功率为50%。如果你想“倾斜”你的分布,只需改变决定是否将1添加到n的行,以便概率不是50%。