首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >为什么我在使用$RANDOM时得到了不均匀的结果?

为什么我在使用$RANDOM时得到了不均匀的结果?
EN

Unix & Linux用户
提问于 2019-07-04 09:10:13
回答 2查看 3.7K关注 0票数 15

我在维基百科上读到了关于RNG的文章,在TLDP上读到了$RANDOM函数,但是它并没有真正解释这个结果:

代码语言:javascript
运行
复制
$ 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个值上?

代码语言:javascript
运行
复制
$ 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
EN

回答 2

Unix & Linux用户

回答已采纳

发布于 2019-07-04 10:02:26

关于模偏的主题,您的公式是:

代码语言:javascript
运行
复制
max=$((6*3600))
$(($RANDOM%max/3600))

在这个公式中,$RANDOM是0-32767范围内的随机值.

代码语言:javascript
运行
复制
   RANDOM Each time this parameter is referenced, a random integer between
          0 and 32767 is generated.

它有助于可视化如何映射到可能的值:

代码语言:javascript
运行
复制
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时,结果是:

代码语言:javascript
运行
复制
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-32767

1-8具有相同的概率,但对0仍然有轻微的偏差,因此,在您的测试中,通过100'000次迭代,0仍然是赢家。

要修正模数偏差,你应该先简化公式(如果你只想要0-5,那么模数是6,而不是3600甚至更疯狂的数字,没有意义)。这一简化将大大减少您的偏差(32766映射到0,32767到1,这两个数字有一个微小的偏差)。

为了完全消除偏倚,您需要重新滚动(例如)当$RANDOM低于32768 % 6时(消除不完全映射到可用随机范围的状态)。

代码语言:javascript
运行
复制
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

测试结果:

代码语言:javascript
运行
复制
  16425 5
  16515 1
  16720 0
  16769 2
  16776 4
  16795 3

另一种方法是使用不同的随机源,它没有明显的偏差(数量级大于32768的可能值)。但是,无论如何,实现重新滚逻辑并不有害(即使它可能永远不会实现)。

票数 37
EN

Unix & Linux用户

发布于 2019-07-04 09:17:05

这是模数偏见。如果RANDOM构造良好,则以相同的概率产生0到32767之间的每个值。使用模块化时,可以更改概率:模块上面所有值的概率都添加到它们映射到的值中。

在您的示例中,6×3600大约是数值范围的三分之二。因此,前三分之一的概率被添加到下三分之一的概率中,这意味着从0到2(大约)的值是从3到5.9×3600的数值的近32767倍,因此模偏压要小得多,并且只影响32400到32767的值。

要回答你的主要问题,至少在巴什随机序列是完全可预测的,如果你知道种子。参见intrand32 in variables.c

票数 23
EN
页面原文内容由Unix & Linux提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://unix.stackexchange.com/questions/528343

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档