我在维基百科上读到了关于RNG的文章,在TLDP上读到了$RANDOM函数,但是它并没有真正解释这个结果:
$ max=$((6*3600))
$ for f in {1..100000}; do echo $(($RANDOM%max/3600)); done | sort | uniq -c
21787 0
22114 1
21933 2
12157 3
10938 4
11071 5为什么在2x以上的值比3,4,5更倾向于0,1,2,但是当我改变最大模时,它们几乎均匀地分布在所有10个值上?
$ max=$((9*3600))
$ for f in {1..100000}; do echo $(($RANDOM%max/3600)); done | sort | uniq -c
11940 0
11199 1
10898 2
10945 3
11239 4
10928 5
10875 6
10759 7
11217 8发布于 2019-07-04 10:02:26
关于模偏的主题,您的公式是:
max=$((6*3600))
$(($RANDOM%max/3600))在这个公式中,$RANDOM是0-32767范围内的随机值.
RANDOM Each time this parameter is referenced, a random integer between
0 and 32767 is generated.它有助于可视化如何映射到可能的值:
0 = 0-3599
1 = 3600-7199
2 = 7200-10799
3 = 10800-14399
4 = 14400-17999
5 = 18000-21599
0 = 21600-25199
1 = 25200-28799
2 = 28800-32399
3 = 32400-32767所以在你的公式中,0,1,2的概率是4,5的两倍,而3的概率也略高于4,5。因此你的结果是0,1,2为赢家,4,5为输家。
当更改为9*3600时,结果是:
0 = 0-3599
1 = 3600-7199
2 = 7200-10799
3 = 10800-14399
4 = 14400-17999
5 = 18000-21599
6 = 21600-25199
7 = 25200-28799
8 = 28800-32399
0 = 32400-327671-8具有相同的概率,但对0仍然有轻微的偏差,因此,在您的测试中,通过100'000次迭代,0仍然是赢家。
要修正模数偏差,你应该先简化公式(如果你只想要0-5,那么模数是6,而不是3600甚至更疯狂的数字,没有意义)。这一简化将大大减少您的偏差(32766映射到0,32767到1,这两个数字有一个微小的偏差)。
为了完全消除偏倚,您需要重新滚动(例如)当$RANDOM低于32768 % 6时(消除不完全映射到可用随机范围的状态)。
max=6
for f in {1..100000}
do
r=$RANDOM
while [ $r -lt $((32768 % $max)) ]; do r=$RANDOM; done
echo $(($r%max))
done | sort | uniq -c | sort -n测试结果:
16425 5
16515 1
16720 0
16769 2
16776 4
16795 3另一种方法是使用不同的随机源,它没有明显的偏差(数量级大于32768的可能值)。但是,无论如何,实现重新滚逻辑并不有害(即使它可能永远不会实现)。
发布于 2019-07-04 09:17:05
这是模数偏见。如果RANDOM构造良好,则以相同的概率产生0到32767之间的每个值。使用模块化时,可以更改概率:模块上面所有值的概率都添加到它们映射到的值中。
在您的示例中,6×3600大约是数值范围的三分之二。因此,前三分之一的概率被添加到下三分之一的概率中,这意味着从0到2(大约)的值是从3到5.9×3600的数值的近32767倍,因此模偏压要小得多,并且只影响32400到32767的值。
要回答你的主要问题,至少在巴什随机序列是完全可预测的,如果你知道种子。参见intrand32 in variables.c。
https://unix.stackexchange.com/questions/528343
复制相似问题