$ RANDOM을 사용할 때 왜 고르지 않은 결과가 나타 납니까?


14

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

9
이에 대한 일반적인 대답은 RANDOM의 최대 값과 모듈로 균등하게 나눌 수있는 가능한 최대 값 사이에있는 경우 다시 롤백 (수신 한 번호를 버리고 다른 번호를 선택)하는 것입니다. 그것은 평범한 -RANDOM이 아니며 모든 언어 / 도구 / 등에서 모듈로-제한 -RNG 도메인을 사용하는 것이 일반적 입니다. 해당 유형의 RNG를 구현합니다.
찰스 더피

7
: 당신이 그것을 얻는 방법 나쁜 멋진 그래프하려면이 편견의 소스에 내 2013 문서를 참조 ericlippert.com/2013/12/16/...
에릭 Lippert의

1
"난수 생성은 너무 중요해서 우연히 남길 수 없습니다." -Robert Coveyou. 참고로하지만 대부분의 프로그램이 진정 난수를 생성 할 수 없습니다
jesse_b을

@Eric Lippert 감사합니다, 기꺼이 읽어 드리겠습니다!
cprn

1
모듈로 바이어스로 인해 문제가 발생하더라도 $RANDOM변수는 내부적으로 좋은 PRNG를 사용 하지 않습니다 .

답변:


36

모듈로 바이어스의 주제를 확장하기 위해 공식은 다음과 같습니다.

max=$((6*3600))
$(($RANDOM%max/3600))

이 공식에서 $RANDOM0-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 가능한 값보다 큰 차수)가없는 다른 임의의 소스를 사용하는 것입니다. 그러나 다시 롤 로직을 구현해도 아무 문제가 없습니다.


"$ RANDOM이 32768 % 6보다 낮을 때 다시 롤업해야 함"은 실제로 "floor ((RANDMAX + 1) / 6) * 6"이상이어야합니다 (예 : 32766). ) 아래의 관련 셸 코드를 수정하십시오.
Nayuki

@Nayuki 특정 오류 (지정된 컨텍스트 내에서 적용됨)를 지적 할 수 있다면 기꺼이 수정하겠습니다. 내 솔루션은 예일 뿐이며 다른 방법이 있습니다. 시작 범위, 종료 범위 또는 중간 어딘가에서 바이어스를 제거 할 수 있습니다. 더 잘 계산할 수 있습니다 (모든 반복에서 모듈로를 수행하지는 않음). 임의 모듈러스 및 randmax 값과 같은 특수한 경우를 처리 할 수 ​​있으며 RANDMAX + 1이없는 RANDMAX = INTMAX도 처리 할 수 ​​있지만 여기서는 그 초점이 아닙니다.
frostschutz

답글이 게시물보다 크게 나쁩니다. 우선, 나는 당신의 어떤 문구가 사실 틀렸는 지 구체적으로 지적했습니다. "32768 % 6"== 2이므로 $ RANDOM <2마다 다시 롤백 하시겠습니까? 시작 / 종료 / 중간 범위의 바이어스와 관련하여 전체 게시물은 범위의 끝에서 바이어스를 제거하는 것입니다. 셋째, RANDMAX = INTMAX 처리에 대해 이야기하지만 대답에서 32768 (= 32767 + 1) 값을 여러 번 언급 했으므로 RANDMAX + 1 계산에 익숙합니다.
Nayuki

1
@Nayuki 내 코드는 0과 1을 제거하고 당신은 32766과 32767을 제거하며 정교하게하고 싶습니다. 어떻게 차이가 있습니까? 나는 인간 일 뿐이고 실수를 저 지르지 만, 지금까지 말한 것은 이유를 설명하거나 보여주지 않고 "잘못되었습니다". 감사합니다.
frostschutz

1
신경 쓰지 마라. 잘못된 경보에 대해 죄송합니다.
Nayuki

23

이것은 모듈로 바이어스입니다. RANDOM제대로 구성된 경우 0에서 32767 사이의 각 값은 동일한 확률로 생성됩니다. 모듈로를 사용하면 확률이 변경됩니다. 모듈로 위의 모든 값의 확률이 매핑 된 값에 추가됩니다.

귀하의 예에서 6x3600은 값 범위의 약 2/3입니다. 따라서 상위 3 분의 1의 확률은 하위 3 분의 3의 확률에 더해집니다. 즉, 0에서 2까지의 값은 3에서 5까지의 값에 비해 생성 될 가능성이 두 배가됩니다. 9 × 3600은 거의 32767이므로 모듈로 바이어스는 훨씬 작으며 32400에서 32767 사이의 값에만 영향을줍니다.

주요 질문에 대답하기 위해, 적어도 Bash에서 시드를 알고 있다면 무작위 시퀀스를 완전히 예측할 수 있습니다. 보기 intrand32에서 variables.c.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.