随机数重新排序的总和合并为重复值

Sums of random number reorderings combine to recurring values

提问人:OverLordGoldDragon 提问时间:8/14/2023 最后编辑:OverLordGoldDragon 更新时间:8/14/2023 访问量:87

问:

g0 = randn(1, 100);
g1 = g0;
g1(2:end) = flip(g1(2:end));
sprintf("%.15e", sum(g0) - sum(g1))
g0 = np.random.randn(100)
g1 = g0.copy()
g1[1:] = g1[1:][::-1]
print(sum(g0) - sum(g1))

在 Python 和 MATLAB 中,重新运行这些命令足够多次将重复以下值(或其否定值;不完整列表):

8.881784197001252e-15
3.552713678800501e-15
2.6645352591003757e-15
4.440892098500626e-16
1.7763568394002505e-15

事实上,我第一次和第二次运行它们 - 它们完全相同,让我认为它们在系统级别上共享 RNG 有延迟......(但忽略这个问题)。mat -> py -> mat -> py

我很快就会摔倒在地板上,而不是这个巧合,再加上不同的语言。

发生了什么事情?


Windows、Python、numpy、MATLAB、113.11.41.24.49.14.0.2286388 (R2023a) Update 3

python numpy matlab 随机 精度

评论

0赞 John BG 8/14/2023
用于 MATLAB 1。尝试使用以下命令重置 RAND 使用的生成器的 35 长状态向量: rand('state',sum(100*clock)) 每次都会将生成器重置为不同的状态。2. rand('state') 返回 35 长向量,该向量是命令 rand 使用的统一生成器的状态。3. 更改生成器的状态:rand('state',s) 将状态重置为 s 4。rand('state',0) 将生成器重置为初始状态 5。rand('state',k) 将生成器重置为第 k 个状态
0赞 JonSG 8/14/2023
退房: stackoverflow.com/questions/588004/...
0赞 OverLordGoldDragon 8/14/2023
@JonSG 它是什么部分?我知道为什么输出不是0
1赞 JonSG 8/14/2023
您遇到了浮点数的默认精度。这是一个示例输出,我还打印了 --> 将最后两个数字减去它们,现在尝试更改第二个数字的最后一位数字,看看你得到了什么。sum(g0)sum(g1)2.220446049250313e-16 1.0386152428024817 1.03861524280248151.0386152428024817 - 1.0386152428024815
1赞 OverLordGoldDragon 8/14/2023
@JonSG啊,单个位 - 浮点 epsilon 的倍数(或类似的东西)......随意发布作为答案。

答:

2赞 Cris Luengo 8/14/2023 #1

您的价值观列表:

8.881784197001252e-15
3.552713678800501e-15
2.6645352591003757e-15
4.440892098500626e-16
1.7763568394002505e-15

比赛

>> [40,16,12,2,8].' * eps

ans =

   1.0e-14 *

   0.888178419700125
   0.355271367880050
   0.266453525910038
   0.044408920985006
   0.177635683940025

完全可以预料到,您会遇到此范围内的舍入误差。在两个不同的系统中获得完全相同的两个值并不是那么大的巧合。这是偶然发生的。

eps是机器 epsilon,您可以将其与 1 相加以获得下一个数字的最小值。添加 100(单位正态)随机值的结果大多恰好在 1-32 范围内,较小的值更有可能。我们还希望舍入误差小于结果的精度。因此,我们应该能够将这些数字写成:<small integer> * eps(<binary magnitude of result>)

8.881784197001252e-15  == 5 * eps(8)
3.552713678800501e-15  == 1 * eps(16)
2.6645352591003757e-15 == 3 * eps(4)
4.440892098500626e-16  == 1 * eps(2)
1.7763568394002505e-15 == 1 * eps(8)

另请注意,MATLAB 最近更改了其 sum 的实现,明确地减少了舍入误差并且 NumPy 使用类似的策略对数组中的值求和

评论

1赞 Cris Luengo 8/14/2023
1e100是一个有效的浮点数,也是。但是,如果将它们加在一起,第二个远低于第一个可以表示的大小,因此结果将等于第一个。想象一下,您有 3 位十进制精度(带有任意指数)。你可以精确地表示 10.0,也可以表示 0.001。将它们相加得到 10.001,但您只有 3 位精度,因此必须将其四舍五入为 10.0。 是 ,您可以将其加到 1 以获得下一个可表示的浮点数的最小值。[续]1e-100epseps(1)
0赞 Cris Luengo 8/14/2023
[续]将 100 个值相加预计会产生一个相对较小的值,可能是 4 个,也许是 16 个。当然,有时它会更大或更小。无论如何,从 4 向上的下一个值是 ,从 16 向上的下一个值是 。这就是您在此处执行的操作的精度。[请注意,我在这里故意使用 2 的幂,5 和 4 在二进制中具有相同的大小。randneps(4) == 4*epseps(16) == 16*epseps(5) == eps(4)
0赞 OverLordGoldDragon 8/15/2023
eps(x)返回 足够不同的唯一值,但不返回任何不同的 的唯一值。 7 到 11,1E6 试验的平均 8.65。我想这是在理性的范围内,尽管我仍然觉得我不太可能经常重复。我想这是更有可能的,因为不同的舍入实现可以取消。还有(2)。-- (1)你说“是有效的浮点”,那么“不能表示为浮点”?-- (2) 有总和内四舍五入,因此我的前 (1) - 另请参阅 sum 与 np.sumxxnumel(unique(eps(randn(1, 100)))) == 1e-100
1赞 Cris Luengo 8/15/2023
@OverLordGoldDragon“是一个无法精确表示的有效浮点数” 您可以表示它,但会有一个小的舍入误差。 无效,则根本无法表示,并且四舍五入为 0。 取决于 的(二进制)数量级,而不是它的确切值。它是数字中最低位的值。当您将指数增加 1 时,最低位的值将加倍。所以 1 和 2 之间的所有数字都是一样的,2 和 4 之间的所有数字都是双倍的,4 和 8 之间的所有数字都是双倍的,依此类推。1e-600eps(x)xeps
1赞 Cris Luengo 8/15/2023
@OverLordGoldDragon 这里有一些关于浮点的更多读物。这是一个非常复杂的话题,有很多细节和陷阱。这是参考,以防你喜欢硬数学。这是那篇论文的简化版(虽然我没有读过,但我不知道它是否足够详细来帮助你)。