根据 PCGRandom 模块中 getNext 的手册页,我们可以生成给定范围内的随机数,例如:
use Random;
var rng1 = new owned RandomStream( eltType= real, seed= 100 );
var rng2 = new owned RandomStream( eltType= int, seed= 100 );
for i in 1..5 do
writeln( rng1.getNext( min= 3.0, max= 5.0 ) );
writeln();
for i in 1..5 do
writeln( rng2.getNext( min= 20, max= 80 ) );
它给出(使用 chpl-1.20.0(:
4.50371
4.85573
4.2246
4.84289
3.63607
36
57
79
39
57
在这里,我注意到手册页对整数和实数情况都给出了以下注释:
对于整数,此类使用一种策略在特定范围内生成值,该值尚未经过严格的研究,并且可能存在统计问题。
对于实数,此类通过计算 [0,1] 中的随机值并缩放和移动该值来生成 [max, min] 中的随机值。请注意,并非区间 [min, max] 中所有可能的浮点值都可以以这种方式构造。
(我用斜体强调(。对于实数,这是否与所谓的"浮点数密度"有关,例如在本页中询问(?另外,对于整数,在某些情况下,即使对于"典型"使用,我们是否需要小心? (这里,"典型"是指,例如,在给定范围内近似平坦分布的 10**8 个随机整数的生成。
仅供参考,我的"用例"不是对随机数的严格质量测试,而只是典型的蒙特卡罗计算(例如,在立方晶格上选择随机站点(。
手册页中的注释表明了与其他PCG随机数方法(至少由PCG算法的作者研究(的不同之处。
浮点数的问题确实与浮点数密度有关。请参阅PCG作者的 http://www.pcg-random.org/using-pcg-c-basic.html#generating-doubles。即使在 [0.0, 1.0] 中生成随机数时,这也是一个潜在的问题。文档中的这一段描述了这个问题:
当生成实数、虚数或复数时,这 实现使用生成 64 位无符号的策略 整数,然后将其乘以 2.0**-64 以将其转换为 浮点数。虽然这确实构建了制服 四舍五入浮点值的分布,它遗漏了许多 可能的实际值(例如,2**-128(。我们相信这一点 策略具有合理的统计属性。一个副作用 这个策略是可以生成实数 1.0,因为 舍入。可以生成实数 0.0,因为 PCG 可以产生 值 0 作为随机整数。
请注意,64 位实数可以存储小至2.0**-1024
的数字,但通过将正整数除以2**64
来获得这样的数字是不可能的。(在这里和上面,我使用**
作为幂运算符,因为这就是它在 Chapel 语法中所做的(。我建议阅读IEEE浮点格式(例如 https://en.wikipedia.org/wiki/IEEE_754 或 https://en.wikipedia.org/wiki/Double-precision_floating-point_format(,以获取该领域的背景信息。如果您使用 RNG 为对real(64)
值进行操作的算法生成测试输入,则可能会关心这一点。在这种情况下,您可能希望生成非常小的值。请注意,构造一个能够以非均匀方式生成所有real(64)
值的 RNG 并不难(例如,只需将位从uint
复制到real
中(。
关于你问题的另一部分:
我用TestU01在一定范围内生成随机整数做了一些基本的统计测试,我对它在蒙特卡罗计算中的使用充满信心。但是,我不是该领域的专家,因此我将该警告放在文档中。文档中的以下信息描述了我所做的测试:
我们已经使用 TestU01 测试了此实现(可在 http://simul.iro.umontreal.ca/testu01/tu01.html (。 我们测量了我们的 使用 TestU01 1.2.3 和 Crush 套件实现,其中包括 的 144 个统计测试。结果是:
- 生成均匀实数没有失败
- 生成 32 位值失败 1 次(对于具有相同配置的 PCG 参考版本也是如此(
- 生成 64 位值失败 0 次(我们将其提供给 TestU01 为 2 不同的 32 位值,因为它一次只接受 32 位(
- 生成有界整数失败 0 次(我们通过请求
[0..,2**31+2**30+1)
中的值提供给 TestU01,直到我们有两个值<2**31,删除前 0 位,然后将前 16 位合并到提供给 TestU01 的值中(。