为什么C++ rand()似乎只生成相同数量级的数字?

Tal*_*ias 146 c c++ random math

在用C/C++编写的小应用程序中,我遇到了一个问题 rand函数也许是种子:

我想生成一系列具有不同顺序的随机数,即具有不同的对数值(基数为2).但似乎所有产生的数字都是相同的顺序,波动在2 ^ 25到2 ^ 30之间.

是因为rand()用Unix时间播种,现在是一个相对较大的数字?我忘记了什么?我rand()只在一开始播种一次main().

C4s*_*tor 478

1到2 30之间只有3%的数字不在2 25和2 30之间.所以,这听起来很正常:)

因为2 25 /2 30 = 2 -5 = 1/32 = 0.03125 = 3.125%

  • @ BlueRaja-DannyPflughoeft - 如果概率很明显,赌场就会破产. (118认同)
  • 是的,好点!感谢快速回答,在2 ^ 25和2 ^ 30之间的数字比在1和2 ^ 25之间多31倍.我需要重新考虑这个程序.问题回答了. (36认同)
  • @BrettHale - 我认为程序员不是赌场的目标人群. (26认同)
  • 我希望这对大多数程序员来说是显而易见的:任何小于2 ^ 25的无符号整数必须使其前7位等于"0" - 如果每个位都是随机的...... (13认同)

Cas*_*Chu 272

较浅的绿色是0到2 25之间的区域; 较深的绿色是2 25和2 30之间的区域.刻度是2的幂.

分配


Bat*_*eba 42

您需要更精确:您需要不同的基数2对数值,但您想要的是什么分布?标准rand()函数生成均匀分布,您需要使用与所需分布关联的分位数函数来转换此输出.

如果您告诉我们分发,那么我们可以告诉您所需的quantile功能.

  • +1,_distribution_是关键术语.当对分布一无所知时,谈论随机数是没有意义的.制服只是一个特例,虽然很重要.可能是一个指出C++ 11标准库中各种发行版的好地方. (13认同)

asp*_*rge 18

如果你想要不同的数量级,为什么不试试pow(2, rand())呢?或者像哈罗德建议的那样直接选择顺序作为rand()?

  • 由于`rand()`可以达到'RAND_MAX`,你真的需要扩展你的随机数,这样结果就不会溢出...... (6认同)
  • 好主意,但你应该使用pow而不是^来解决你的答案(这是逻辑xor运算符,而不是幂,在C语言中). (3认同)

Fra*_*cia 13

@ C4stor提出了一个很好的观点.但是,对于更一般的情况并且更容易理解人类(基数10):对于1到10 ^ n的范围,~90%的数字是从10 ^(n-1)到10 ^ n,因此, ~99%的数字从10 ^(n-2)到10 ^ n.继续添加任意数量的小数.

有趣的数学,如果你继续这样做n,你可以看到从1到10 ^ n,99.9999 ...%= 100%的数字是从10 ^ 0到10 ^ n用这种方法.

现在关于代码,如果你想要一个随机数量的随机数,从0到10 ^ n,你可以这样做:

  1. 生成从0到n的小随机数

  2. 如果您知道n的范围,则生成一个10 ^ k的大随机数,其中k> max {n}.

  3. 剪下较长的随机数,得到这个大随机数的n位数.

  • 你完全正确,但是对于一个非常容易理解的答案,OP应该问自己为什么90%的1到100之间的随机数是两位数. (46认同)

Flo*_*ris 13

上面已经给出并接受了基本(和正确)答案:0到9之间有10个数字,10到99之间有90个数字,100到999之间有900个数字等.

为了获得具有近似对数分布的分布的计算有效方法,您希望将随机数右移一个随机数:

s = rand() & 31; // a random number between 0 and 31 inclusive, assuming RAND_MAX = 2^32-1
r = rand() >> s; // right shift
Run Code Online (Sandbox Code Playgroud)

它并不完美,但它比计算速度快得多pow(2, rand()*scalefactor).从某种意义上讲,它将是"块状的",因为对于2到2的数字(128到255的均匀,256到1023的密度的一半等),分布将是均匀的.

以下是数字0到31的频率的直方图(在1M样本中):

在此输入图像描述

  • 我并不是说你的代码是错的.这可能就是我要做的.它只是值得警告,结果不像人们预期的那样_quite_分布. (2认同)

Vad*_*dim 5

0到2 ^ 29和2 ^ 29和2 ^ 30之间的数字完全相同.

查看问题的另一种方法是:考虑生成的随机数的二进制表示,最高位为1的概率等于1/2,因此,在一半的情况下得到29阶.你想要的是看到一个低于2 ^ 25的数字,但这意味着5个最高位都是零,这发生在1/32的低概率.有可能即使你长时间运行它,你也永远不会看到低于15的顺序(概率就像是连续6次滚动6次).

现在,关于种子问题的一部分.不,种子不可能确定生成数字的范围,它只是确定第一个初始元素.将rand()视为范围内所有可能数字的序列(预定排列).种子确定从序列中开始绘制数字的位置.这就是为什么如果你想要(伪)随机性,你使用当前时间来初始化序列:你不关心你开始的位置是不是均匀分布,重要的是你永远不会从同一个位置开始.