在一个用 C/C++ 编写的小型应用程序中,我遇到了rand
函数问题,也许是种子问题:
我想产生一系列不同阶的随机数,即具有不同的对数值(以 2 为底)。但似乎所有产生的数字都是相同的顺序,只是在 2^25 和 2^30 之间波动。
是不是因为rand()
是用 Unix 时间播种的,现在这个数字比较大?我忘记了什么?我rand()
只在开始时播种一次main()
。
在 1 和 2 30之间只有 3% 的数字不在 2 25和 2 30之间。所以,这听起来很正常:)
因为 2 25 / 2 30 = 2 -5 = 1/32 = 0.03125 = 3.125%
较浅的绿色是 0 到 2 25之间的区域;较深的绿色是 2 25和 2 30之间的区域。刻度是 2 的幂。
你需要更精确:你想要不同的以 2 为底的对数值,但你想要什么样的分布?标准 rand() 函数生成均匀分布,您需要使用与所需分布关联的分位数函数来转换此输出。
如果您告诉我们分布,那么我们可以告诉您quantile
您需要的功能。
如果您想要不同的数量级,为什么不简单地尝试一下pow(2, rand())
?或者也许像 Harold 建议的那样直接选择订单作为 rand()?
上面已经给出并接受了基本(和正确)的答案: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
它并不完美,但比计算快得多pow(2, rand()*scalefactor)
。从某种意义上说,它将是“块状”的,因为因子 2 内的数字分布将是均匀的(128 到 255 是均匀的,256 到 1023 是密度的一半,等等)。
这是数字 0 到 31 的频率的直方图(在 1M 样本中):
@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,你可以这样做:
生成一个从 0 到 n 的小随机数
如果您知道 n 的范围,请生成一个 10^k 阶的大随机数,其中 k > max{n}。
剪下较长的随机数,得到这个大随机数的 n 位。
在 0 和 2^29 以及 2^29 和 2^30 之间存在完全相同的数字。
另一种看待问题的方法:考虑您生成的随机数的二进制表示,最高位为 1 的概率等于 1/2,因此,在一半的情况下您得到 29 阶。你想要的是看到一个低于 2^25 的数字,但这意味着 5 个最高位全为零,这种情况发生的概率很低,只有 1/32。很有可能,即使你运行了很长时间,你也永远不会看到低于 15 的顺序(概率类似于连续滚动 6 6 次)。
现在,关于种子的部分问题。不,种子不可能确定生成数字的范围,它只是确定第一个初始元素。将 rand() 视为范围内所有可能数字的序列(预定排列)。种子决定了您从序列中开始绘制数字的位置。这就是为什么如果你想要(伪)随机性,你使用当前时间来初始化序列:你不关心你开始的位置不是均匀分布的,重要的是你永远不会从同一个位置开始。
使用
pow(2,rand())
它将按所需数量级给出答案!
如果您想使用在线服务中的随机数,您可以使用 wget,您可能希望看到您也可以使用 random.org 等服务来生成随机数,您可以使用 wget 捕获它们,然后从下载的文件
wget -q https://www.random.org/integers/?num=100&min=1&max=100&col=5&base=10&format=html&rnd=new -O new.txt
http://programmingconsole.blogspot.in/2013/11/a-better-and-different-way-to-generate.html