Random

為什麼我在使用 $RANDOM 時會得到分佈不均的結果?

  • July 5, 2019

我在Wikipedia上閱讀了有關 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

為什麼大約 2 倍以上的值比 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

為了擴展模偏差的主題,您的公式是:

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-32767

1-8 具有相同的機率,但對於 0 仍然存在輕微偏差,因此 0 在 100'000 次迭代的測試中仍然是獲勝者。

要修復模數偏差,您應該首先簡化公式(如果您只想要 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 個可能值)。但是無論如何實施重滾邏輯並沒有什麼壞處(即使它可能永遠不會通過)。

引用自:https://unix.stackexchange.com/questions/528343