Để mở rộng về chủ đề thiên vị modulo, công thức của bạn là:
max=$((6*3600))
$(($RANDOM%max/3600))
Và trong công thức này, $RANDOM
là một giá trị ngẫu nhiên trong phạm vi 0-32767.
RANDOM Each time this parameter is referenced, a random integer between
0 and 32767 is generated.
Nó giúp hình dung làm thế nào bản đồ này đến các giá trị có thể:
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
Vì vậy, trong công thức của bạn, xác suất cho 0, 1, 2 gấp đôi so với 4, 5. Và xác suất của 3 cũng cao hơn 4, 5 một chút. Do đó, kết quả của bạn với 0, 1, 2 là người chiến thắng và 4, 5 là người thua cuộc.
Khi đổi thành 9*3600
, hóa ra là:
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 có cùng xác suất, nhưng vẫn có sai lệch nhỏ cho 0 và do đó 0 vẫn là người chiến thắng trong bài kiểm tra của bạn với 100'000 lần lặp.
Để khắc phục sai lệch modulo, trước tiên bạn nên đơn giản hóa công thức (nếu bạn chỉ muốn 0-5 thì modulo là 6, không phải 3600 hoặc thậm chí là số điên hơn, không có ý nghĩa gì trong đó). Chỉ riêng việc đơn giản hóa này sẽ làm giảm rất nhiều sự thiên vị của bạn (32766 ánh xạ thành 0, 32767 thành 1 tạo ra sự thiên vị nhỏ cho hai số đó).
Để loại bỏ hoàn toàn sai lệch, bạn cần cuộn lại, (ví dụ) khi $RANDOM
thấp hơn 32768 % 6
(loại bỏ các trạng thái không ánh xạ hoàn hảo đến phạm vi ngẫu nhiên có sẵn).
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
Kết quả kiểm tra:
16425 5
16515 1
16720 0
16769 2
16776 4
16795 3
Giải pháp thay thế sẽ là sử dụng một nguồn ngẫu nhiên khác nhau không có sai lệch đáng chú ý (các đơn đặt hàng có cường độ lớn hơn chỉ có 32768 giá trị có thể). Nhưng dù sao thì việc thực hiện logic cuộn lại cũng không gây hại gì (ngay cả khi nó có thể không bao giờ được thông qua).