1–5에서 1–7까지 임의 범위 확장


693

1에서 5 사이의 난수를 생성하는 함수가 주어지면 1에서 7 사이의 난수를 생성하는 함수를 작성하십시오.

  1. 간단한 해결책은 무엇입니까?
  2. 메모리 사용량을 줄이거 나 더 느린 CPU에서 실행하는 효과적인 솔루션은 무엇입니까?

예상치 못한 흥미로운 문제로 판명되었습니다. 나는 여전히 1) 정해진 시간에 그것을하고 2) 균일 분포를
망치지

주사위로 5 명 중 1 명을 고르는 동안 비슷한 문제가있었습니다. 우리는 주사위를 교대로 던졌고, 최대 점수를 얻은 사람이 선택되었습니다. 균일 성은 achived 되었으나없는 시간 constantness :
eugensk

문제가 주어진 함수를 사용해야한다고 요구하지 않고 1-7을 무작위로 반환하는 함수를 작성해야한다는 답변을 게시하면 다운 투표를 받습니까?
닥터 블루

무엇에 대해 7 * rand5() / 5?
kiwixz

@kiwixz는 "1과 7 사이"를 생성하지만 수동으로 3 또는 6을 얻지 못합니다. {1 : 19.96, 2 : 20.02, 4 : 20.01, 5 : 19.99, 7 : 20.02} 대략적인 백분율 테스트. 7 * .2, 7 * .4, 7 * .6, 7 * .8, 7 * 1.
pythonlarry

답변:


572

이것은 Adam Rosenfield의 솔루션과 동일하지만 일부 독자에게는 더 분명 할 수 있습니다. rand5 ()는 1에서 5까지의 범위에서 통계적으로 임의의 정수를 리턴하는 함수라고 가정합니다.

int rand7()
{
    int vals[5][5] = {
        { 1, 2, 3, 4, 5 },
        { 6, 7, 1, 2, 3 },
        { 4, 5, 6, 7, 1 },
        { 2, 3, 4, 5, 6 },
        { 7, 0, 0, 0, 0 }
    };

    int result = 0;
    while (result == 0)
    {
        int i = rand5();
        int j = rand5();
        result = vals[i-1][j-1];
    }
    return result;
}

어떻게 작동합니까? 이것을 다음과 같이 생각하십시오. 종이에이 2 차원 배열을 인쇄하여 다트 판에 꽂아 무작위로 다트를 던지는 것을 상상해보십시오. 0이 아닌 값에 도달하면 선택할 수있는 0이 아닌 값의 수가 동일하므로 1에서 7 사이의 통계적으로 임의의 값입니다. 당신이 0을 명중하면, 당신이 0이 아닌 때까지 다트를 계속 던지십시오. 이것이 바로이 코드가하는 일입니다. i와 j 인덱스는 다트 판에서 무작위로 위치를 선택하고 좋은 결과를 얻지 못하면 다트를 계속 던집니다.

Adam이 말했듯이 최악의 경우에는 영원히 실행될 수 있지만 통계적으로 최악의 경우는 발생하지 않습니다. :)


5
이 솔루션의 논리를 이해했지만 어떻게 균일 한 확률을 얻는 지 이해할 수 없습니까? 누군가 수학을 설명 할 수 있습니까?
user1071840

6
@ user1071840- rand5균일 한 경우 vals그리드의 모든 셀 이 선택 될 확률이 동일합니다. 그리드에는 [1, 7] 간격의 각 정수에 대해 정확히 3 개의 사본과 4 개의 0이 포함됩니다. 따라서 "원시"결과 스트림은 [1, 7] 값과 임의의 개별 허용 값보다 더 빈번하게 발생하는 0을 혼합하는 경향이 있습니다. 그러나 0이 제거되어 [1, 7] 값이 균등하게 혼합되기 때문에 문제가되지 않습니다.
다니엘 Earwicker

3
rand5 ()를 한 번만 호출하면 가능한 결과는 5 개뿐입니다. 더 많은 무작위성을 추가하지 않고 5 가지 이상의 결과로 바꿀 수있는 방법은 없습니다.
Daniel Earwicker

1
더 긴 버전 : rand5 ()는 (1, 2, 3, 4, 5) 값만 가질 수 있습니다. 따라서 rand5 () * 5는 값 (5, 10, 15, 20, 25) 만 가질 수 있으며 전체 범위 (1 ... 25)와 동일하지 않습니다. 그렇다면 4를 빼면 (-3 ... 21)이되지만이 경우 (1, 6, 11, 16, 21)이되므로 끝 점이 정확하지만 큰 구멍이 4 개 있습니다. 2..5), (7..10), (12..15), (17..21). 마지막으로 mod 7을 수행하고 1을 추가하여 (2, 7, 5, 3, 1)을 제공하십시오. 따라서 4도 6도 발생하지 않습니다. 그러나 (위의 바로 가기 참조) 결과 범위에 5 개의 숫자 만있을 수 있다는 것을 알았으므로 두 개의 간격이 있어야했습니다.
Daniel Earwicker

1
아, rand2 () :-)가 아닌 rand5 () 만 가지고 있기 때문에
gzak

353

1/7은 밑이 5 인 무한 자릿수이므로 1/7은 일정한 시간에 실행되는 (정확한) 솔루션은 없습니다. 간단한 샘플링 방법은 다음과 같습니다.


int i;
do
{
  i = 5 * (rand5() - 1) + rand5();  // i is now uniformly random between 1 and 25
} while(i > 21);
// i is now uniformly random between 1 and 21
return i % 7 + 1;  // result is now uniformly random between 1 and 7

이것은 루프의 25/21 = 1.19 반복의 예상 런타임을 갖지만, 영원히 반복 될 가능성은 무한히 작습니다.


7
-21이> 26 b / c로 뒤집 히면 -1이 필요하지 않습니다. 하한 맵의 위치는 중요하지 않습니다.
BCS

26
왜 이것이 올바른지 설명합니다 .1에서 25까지 균일 한 난수 스트림을 출력하는 프로그램을 작성하고 싶다고 가정하십시오. 이를 위해 답의 코드에서와 같이 5 * (rand5 ()-1) + rand5 ()를 반환합니다. 이제 1에서 21 사이의 균일 한 난수 스트림을 작성하려면 첫 번째 스트림을 사용하고 [22, 25]의 숫자가 거부되도록 필터링하면 해당 스트림도 작성할 수 있습니다. 다음으로,이 스트림을 가져 와서 각 요소 x에 대해 x % 7 + 1을 출력하도록 필터링하면 1에서 7까지 균일 한 난수 스트림이 있습니다! 아주 간단하지 않습니까? : D
Paggas 2009

6
그리고 무한한 최악의 런타임으로 완벽한 분포를 원하는지 또는 제한된 런타임으로 불완전한 분포를 원하는지에 따라 요약됩니다. 이것은 모든 거듭 제곱 5를 7로 나눌 수 없거나 동등하게 길이 n의 5 ^ n 시퀀스를 갖는 경우 각 시퀀스에 1에서 7까지의 숫자를 할당 할 수있는 방법이 없기 때문입니다. 1..7도 똑같을 것입니다.
Adam Rosenfield

5
@ 줄스 올 레온 (Jules Olléon) : 최악의 경우에만 N전화를 걸 수있는 솔루션이 일정 시간 동안 실행되고 있다고 가정 rand5()합니다. 그런 다음에 대한 호출 순서의 5 ^ N 가능한 결과가 있으며 rand5각 결과는 1-7입니다. 따라서 출력이 k각각 1≤k≤7 인 가능한 모든 호출 시퀀스를 합하면 출력 확률 k은 m / 5 ^ N입니다. 여기서 m은 이러한 시퀀스의 수입니다. 따라서 m / 5 ^ N = 1/7이지만이 ==> 모순에 대한 정수 솔루션 (N, m)은 없습니다.
Adam Rosenfield

4
@paxdiablo : 잘못되었습니다. 진정한 RNG가 무한한 5의 시퀀스를 생성 할 확률은 정확히 0이며, 동전을 무한한 횟수만큼 뒤집는 것이 무한한 연속 헤드를 생성하지 않는다는 사실과 유사한 추론을 사용 합니다 . 이것은 또한이 코드가 영원히 반복 될 확률이 정확히 0임을 의미합니다 (임의의 반복 횟수에 대해 반복 될 긍정적 인 기회가 있음).
BlueRaja-대니 Pflughoeft

153

첫 번째 답변 외에도 다른 답변을 추가하고 싶습니다 . 이 답변은의 사용 횟수를 최대화하기 위해에 대한 호출 rand5()당 호출 횟수를 최소화하려고 rand7()합니다. 즉, 임의성을 귀중한 자원으로 생각하면 임의의 비트를 버리지 않고 최대한 많은 리소스를 사용하려고합니다. 이 답변은 Ivan의 답변 에서 제시된 논리와 유사합니다 .

랜덤 변수엔트로피는 잘 정의 된 수량입니다. 확률이 동일한 N 상태 (균일 분포)를 갖는 랜덤 변수의 경우, 엔트로피는 log 2 N입니다. 따라서, rand5()대략 2.32193 비트의 엔트로피를 rand7()가지며, 약 2.80735 비트의 엔트로피를 갖습니다. 임의성을 최대한 활용하려면 각 호출에서에 2.32193 비트의 엔트로피를 모두 사용하고에 호출 할 rand5()때마다 필요한 2.80735 비트의 엔트로피를 적용해야합니다 rand7(). 그러므로 근본적인 한계는에 대한 호출 rand5()당 log (7) / log (5) = 1.20906 호출보다 더 나은 것을 할 수 없다는 것 rand7()입니다.

참고 사항 : 별도로 지정하지 않는 한이 답변의 모든 로그는 2 밑이됩니다. rand5()는 [0, 4] rand7()범위의 숫자를 반환한다고 가정하고 [0, 6] 범위의 숫자를 반환한다고 가정합니다. 범위를 각각 [1, 5] 및 [1, 7]로 조정하는 것은 쉽지 않습니다.

그래서 우리는 어떻게합니까? 우리는 0과 1 사이 에서 무한정의 정확한 실수를 생성합니다 (실제로 정확한 수를 계산하고 저장할 수있는 척합니다. 나중에 수정하겠습니다). 우리는베이스 (5)에 그 자리를 생성하여 이러한 숫자를 생성 할 수있다 : 우리는 난수 선택 0 a1 a2 a3 ..., 각 디지트 A를 i호출하여 선택에게 rand5(). 예를 들어, RNG가 iall에 대해 = 1을 선택한 경우 i매우 무작위 적이 지 않다는 사실을 무시하면 실수 1/5 + 1/5 2 + 1/5 3 + ... = 1/4 (기하학적 계열의 합).

자, 우리는 0과 1 사이의 난수를 선택했습니다. 이제 난수는 균일하게 분포되어 있다고 주장합니다. 직관적으로, 이것은 각 숫자가 균일하게 선택되고 숫자가 무한정 정확하기 때문에 이해하기 쉽습니다. 그러나 이산 분포 대신 연속 분포를 다루고 있기 때문에 이것에 대한 공식적인 증거가 다소 복잡합니다. 따라서 우리는 우리의 숫자가 구간 [ a, b] 에있을 확률이 길이와 같음 을 증명해야합니다 그 간격 b - a. 증거는 독자를위한 연습으로 남겨둔다 =).

이제 [0, 1] 범위에서 균일 한 난수를 선택 했으므로의 출력을 생성하려면 [0, 6] 범위의 일련의 균일 한 난수로 변환해야합니다 rand7(). 우리는 이것을 어떻게합니까? 우리가 방금했던 것의 반대입니다-우리는 그것을 기초 7에서 무한정 정확한 10 진수로 변환 한 다음, 각각의 기초 7 자리는의 하나의 출력에 해당합니다 rand7().

앞에서 예를 들자면 rand5()무한 스트림 1을 생성하면 임의의 실수는 1/4이됩니다. 1/4을 밑 7로 변환하면 무한 십진수 0.15151515 ...를 얻으므로 출력 1, 5, 1, 5, 1, 5 등으로 생성합니다.

자, 우리는 주된 아이디어를 가지고 있지만 두 가지 문제가 남아 있습니다. 실제로 무한한 정확한 실수를 계산하거나 저장할 수 없기 때문에 유한 부분 만 처리하는 방법은 무엇입니까? 둘째, 우리는 그것을 어떻게 기본 7로 변환합니까?

0과 1 사이의 숫자를 밑수 7로 변환 할 수있는 한 가지 방법은 다음과 같습니다.

  1. 7 곱하기
  2. 결과의 필수 부분은 다음 기본 7 자리입니다.
  3. 분수 부분 만 남기고 정수 부분을 빼십시오
  4. 1 단계로 이동

무한 정밀도 문제를 해결하기 위해 부분 결과를 계산하고 결과의 상한을 저장합니다. 즉, rand5()두 번 전화 했고 두 번 모두 1을 반환 했다고 가정 합니다. 지금까지 생성 한 숫자는 0.11 (기본 5)입니다. rand5()생성 하기 위한 나머지 무한 호출의 나머지가 무엇이든, 우리가 생성하는 임의의 실수는 절대 0.12보다 크지 않습니다. 항상 0.11 ≤ 0.11xyz ... <0.12입니다.

따라서 지금까지의 현재 숫자와 최대 값을 추적하여 숫자를 모두 기본 7 로 변환 합니다 . 첫 번째 k숫자 에 동의 하면 다음 k숫자를 안전하게 출력 할 수 있습니다 . 기본 5 자리의 무한 스트림은 k기본 7 표현 의 다음 자리에 영향을 미치지 않습니다 !

그리고 그것은 알고리즘입니다-의 다음 출력을 rand7()생성 rand5()하기 위해, 우리는 난수를 기본 7로 변환 할 때 다음 숫자의 값을 확실하게 알 수 있도록 필요한 만큼만 ​​자릿수를 생성합니다 . 테스트 하네스가있는 Python 구현 :

import random

rand5_calls = 0
def rand5():
    global rand5_calls
    rand5_calls += 1
    return random.randint(0, 4)

def rand7_gen():
    state = 0
    pow5 = 1
    pow7 = 7
    while True:
        if state / pow5 == (state + pow7) / pow5:
            result = state / pow5
            state = (state - result * pow5) * 7
            pow7 *= 7
            yield result
        else:
            state = 5 * state + pow7 * rand5()
            pow5 *= 5

if __name__ == '__main__':
    r7 = rand7_gen()
    N = 10000
    x = list(next(r7) for i in range(N))
    distr = [x.count(i) for i in range(7)]
    expmean = N / 7.0
    expstddev = math.sqrt(N * (1.0/7.0) * (6.0/7.0))

    print '%d TRIALS' % N
    print 'Expected mean: %.1f' % expmean
    print 'Expected standard deviation: %.1f' % expstddev
    print
    print 'DISTRIBUTION:'
    for i in range(7):
        print '%d: %d   (%+.3f stddevs)' % (i, distr[i], (distr[i] - expmean) / expstddev)
    print
    print 'Calls to rand5: %d (average of %f per call to rand7)' % (rand5_calls, float(rand5_calls) / N)

rand7_gen()숫자를 기본 7로 변환하는 내부 상태가 있으므로 생성기 를 반환합니다. 테스트 하네스는 next(r7)10000 번 호출 하여 10000 개의 난수를 생성 한 다음 분포를 측정합니다. 정수 수학 만 사용되므로 결과가 정확합니다.

또한 여기의 숫자는 매우 커지고 매우 빠릅니다. 5와 7의 거듭 제곱이 빠르게 커집니다. 따라서 큰 수의 산술로 인해 많은 난수를 생성 한 후 성능이 눈에 띄게 저하되기 시작합니다. 그러나 여기서 목표는 성능을 최대화하지 않고 임의의 비트 사용을 최대화하는 것이 었습니다 (이차 목표 임에도 불구하고).

한 번의 실행으로 rand5()10000 번의 호출에 대해 12091 번의 호출을 수행 rand7()하여 평균 log (7) / log (5) 호출의 최소값을 평균 4 개의 유효 숫자로 달성했으며 결과 출력은 균일했습니다.

포트 위해서 임의의 큰 정수가 내장되어 있지 않은 언어 코드, 당신은의 값을 모자해야 pow5하고 pow7네이티브 통합 유형의 최대 값 - 그들은 너무 커질 경우, 다음 재설정 모든 것을 시작합니다. 이렇게하면 호출 rand5()당 평균 호출 수가 rand7()매우 약간 증가하지만 32 비트 또는 64 비트 정수의 경우에도 너무 많이 증가하지 않아야합니다.


7
정말 흥미로운 답변은 +1입니다. 특정 값으로 재설정하는 대신 사용 된 비트를 단순히 시프트하고 다른 비트를 위로 이동하고 기본적으로 사용될 비트 만 유지하는 것이 가능합니까? 아니면 뭔가 빠졌습니까?
Chris Lutz

1
100 % 확신 할 수는 없지만, 그렇게하면 분포가 약간 왜곡 될 수 있습니다 (수많은 시련없이 측정 할 수 있을지 의심 스럽지만).
Adam Rosenfield

FTW! 5의 거듭 제곱에 7의 거듭 제곱과 공통 인 요소가 없기 때문에 큰 숫자를 더 작게 만들려고 시도했지만 수행 할 수 없습니다! 또한 yield 키워드를 잘 사용하십시오. 잘 했어요
Eyal

2
아주 좋아요! 상태를 키우지 않고도 여분의 엔트로피를 유지할 수 있습니까? 트릭은 상한과 하한이 항상 합리적임을 알 수 있습니다. 우리는 정밀도를 잃지 않고 이것을 더하고 빼고 곱할 수 있습니다. 우리가 35 번 기지에서이 모든 것을하면 거의 다 왔습니다. 나머지 (7을 곱하고 소수 부분 유지)는 연습으로 남습니다.
Ian

@adam "pow5 및 pow7의 값을 기본 정수 유형의 최대 값으로 제한"을 참조해야합니다. 나는 이것이 순진하게 끝나면 분포가 왜곡 될 것이라고 믿습니다.
촉매

36

( Adam Rosenfeld의 답변 을 훔쳐서 약 7 % 빠르게 실행했습니다.)

rand5 ()가 등분 포가있는 {0,1,2,3,4} 중 하나를 리턴하고 목표가 등분 포가있는 {0,1,2,3,4,5,6}을 리턴한다고 가정하십시오.

int rand7() {
  i = 5 * rand5() + rand5();
  max = 25;
  //i is uniform among {0 ... max-1}
  while(i < max%7) {
    //i is uniform among {0 ... (max%7 - 1)}
    i *= 5;
    i += rand5(); //i is uniform {0 ... (((max%7)*5) - 1)}
    max %= 7;
    max *= 5; //once again, i is uniform among {0 ... max-1}
  }
  return(i%7);
}

루프가 variable에서 만들 수있는 가장 큰 값을 추적합니다 max. 지금까지의 결과가 max % 7과 max-1 사이이면 결과가 해당 범위에서 균일하게 분산됩니다. 그렇지 않으면 0과 max % 7-1 사이의 임의의 나머지와 rand ()에 대한 또 다른 호출을 사용하여 새 숫자와 새 max를 만듭니다. 그런 다음 다시 시작합니다.

편집 :이 방정식에서 rand5 ()가 x 인 호출 횟수는 x입니다.

x =  2     * 21/25
   + 3     *  4/25 * 14/20
   + 4     *  4/25 *  6/20 * 28/30
   + 5     *  4/25 *  6/20 *  2/30 * 7/10
   + 6     *  4/25 *  6/20 *  2/30 * 3/10 * 14/15
   + (6+x) *  4/25 *  6/20 *  2/30 * 3/10 *  1/15
x = about 2.21 calls to rand5()

2
1,000,000 회 시도로 분류 된 결과 : 1 = 47216; 2 = 127444; 3 = 141407; 4 = 221453; 5 = 127479; 6 = 167536; 7 = 167465. 보다시피, 1을 얻는 확률과 관련하여 분배가 부족하다.
Robert K

2
@ 악한 벼룩 : 나는 당신이 잘못 생각합니다. 이 솔루션에 지정된대로 테스트에 사용했던 입력 rand5 ()가 1-5 대신 0-4를 생성 했습니까?
Adam Rosenfield

5
균일하게 분포 된 숫자를 추가해도 균일하게 분포 된 숫자는 아닙니다. 실제로, 정규 분포에 대한 합리적인 근사치를 얻으려면 이러한 균일하게 분포 된 변수 6 개만 합하면됩니다.
Mitch Wheat

2
@MitchWheat-두 개의 균일하게 분포 된 정수를 추가하면 실제로 각 가능한 합계가 정확히 한 가지 방식으로 생성 될 수있는 경우 균일하게 분포 된 임의의 정수가됩니다. 그것은 표현에서 그렇습니다 5 * rand5() + rand5().
Ted Hopp

28

연산:

7은 3 비트의 시퀀스로 표현 될 수있다

rand (5)를 사용하여 각 비트를 0 또는 1로 무작위로 채 웁니다.
예를 들어 : rand (5)를 호출하고

결과가 1 또는 2 인
경우 결과가 4 또는 5 인 경우 비트를 0으로 채우고
결과가 3 인 경우 비트를 1로 채우고 무시하고 다시 수행하십시오 (거부)

이 방법으로 3 비트를 0/1로 무작위로 채울 수 있으므로 1-7에서 숫자를 얻을 수 있습니다.

편집 : 이것은 가장 간단하고 가장 효율적인 답변처럼 보입니다. 그래서 여기에 대한 코드가 있습니다.

public static int random_7() {
    int returnValue = 0;
    while (returnValue == 0) {
        for (int i = 1; i <= 3; i++) {
            returnValue = (returnValue << 1) + random_5_output_2();
        }
    }
    return returnValue;
}

private static int random_5_output_2() {
    while (true) {
        int flip = random_5();

        if (flip < 3) {
            return 0;
        }
        else if (flip > 3) {
            return 1;
        }
    }
}

1
가난한 난수 생성기가 특정 지점에서 많은 수 의 3을 생성 할 수 있기 때문에 항상 정지 문제의 희미한 스펙터가 있습니다.
Alex North-Keys

"결과가 1 또는 2 인 경우 결과가 4 또는 5 인 경우 비트를 0으로 채우고 비트를 1로 채우십시오"1,2,4,5가 수락되고 3이 거부 된 논리는 무엇입니까? 이것을 설명 할 수 있습니까?
gkns

@gkns 논리가 없으므로 0 비트로 1 및 2 평균 채우기를, 1로 3 및 4 평균 채우기를 가질 수 있습니다. 중요한 것은 각 옵션에 50 %의 확률이 있으므로 함수의 임의성이 보장됩니다. 최소한 원래 rand (5) 함수만큼 무작위입니다. 훌륭한 솔루션입니다!
Mo Beigi

이것은 간단하거나 효율적이지 않습니다. random_7 당 random_5까지의 cal 수는 일반적으로 3 이상입니다. 이 페이지의 다른 솔루션은 실제로 약 2.2에 가깝습니다.
Eyal

1
신경 끄시 고, 나는 "에 ReturnValue 동안 == 0"부분을 놓친
NicholasFolk

19
int randbit( void )
{
    while( 1 )
    {
        int r = rand5();
        if( r <= 4 ) return(r & 1);
    }
}

int randint( int nbits )
{
    int result = 0;
    while( nbits-- )
    {
        result = (result<<1) | randbit();
    }
    return( result );
}

int rand7( void )
{
    while( 1 )
    {
        int r = randint( 3 ) + 1;
        if( r <= 7 ) return( r );
    }
}

2
rand7 () 호출마다 rand5 ()에 대해 평균 30/7 = 4.29 호출을 수행하는 올바른 솔루션입니다.
Adam Rosenfield

17
rand7() = (rand5()+rand5()+rand5()+rand5()+rand5()+rand5()+rand5())%7+1

편집 : 그것은 작동하지 않습니다. 1000에서 약 2 개의 부품이 사용됩니다 (완벽한 rand5를 가정). 버킷은 다음을 얻습니다.

value   Count  Error%
1       11158  -0.0035
2       11144  -0.0214
3       11144  -0.0214
4       11158  -0.0035
5       11172  +0.0144
6       11177  +0.0208
7       11172  +0.0144

합으로 전환하여

n   Error%
10  +/- 1e-3,
12  +/- 1e-4,
14  +/- 1e-5,
16  +/- 1e-6,
...
28  +/- 3e-11

2를 추가 할 때마다 크기가 커지는 것 같습니다.

BTW : 위의 오류 테이블은 샘플링을 통해 생성되지 않고 다음과 같은 반복 관계에 의해 생성되었습니다.

p[x,n]에 전화를 걸면 output=x발생할 수 있는 여러 가지 방법 입니다.nrand5

  p[1,1] ... p[5,1] = 1
  p[6,1] ... p[7,1] = 0

  p[1,n] = p[7,n-1] + p[6,n-1] + p[5,n-1] + p[4,n-1] + p[3,n-1]
  p[2,n] = p[1,n-1] + p[7,n-1] + p[6,n-1] + p[5,n-1] + p[4,n-1]
  p[3,n] = p[2,n-1] + p[1,n-1] + p[7,n-1] + p[6,n-1] + p[5,n-1]
  p[4,n] = p[3,n-1] + p[2,n-1] + p[1,n-1] + p[7,n-1] + p[6,n-1]
  p[5,n] = p[4,n-1] + p[3,n-1] + p[2,n-1] + p[1,n-1] + p[7,n-1]
  p[6,n] = p[5,n-1] + p[4,n-1] + p[3,n-1] + p[2,n-1] + p[1,n-1]
  p[7,n] = p[6,n-1] + p[5,n-1] + p[4,n-1] + p[3,n-1] + p[2,n-1]

8
이것은 균일 한 분포가 아닙니다. 그것은 균일에 매우 가깝지만 완벽하게 균일하지는 않습니다.
Adam Rosenfield

아! 주사위와 7. 당신이 내가 틀렸다고 말할 것이라면, 그 증거를 독자를위한 연습으로 남겨 두지 말아야합니다.
BCS

45
그것이 균등하지 않다는 증거는 간단합니다 : 무작위성이 될 수있는 5 ^ 7 가지 방법이 있으며, 5 ^ 7이 7의 배수가 아니기 때문에 7 개의 합계가 똑같을 가능성은 없습니다. (기본적으로 7은 5에서 상대적으로 소수이거나 5에서 종료하는 소수가 아닌 1/7로 감소합니다.) 실제로이 제약 조건에서 "가장 균일하지 않음"도 아닙니다. 직접 계산은 5 ^ 7 = 78125 합, 1에서 7까지의 값을 얻는 횟수는 {1 : 11145, 2 : 11120, 3 : 11120, 4 : 11145, 5 : 11190, 6 : 11215, 7 : 11190}입니다.
ShreevatsaR

@ShreevatsaR rand5 ()의 합계를 7 번 취하는 대신 5 * 7이 걸리면 어떻게됩니까? 35 ^ 7 % 7 = 35 ^ 5 % 7 = 0
kba

4
@KristianAntonsen : rand5 ()를 몇 번이나하더라도 균일 한 분포를 얻지 못할 것입니다. N 번 수행하면 5 ^ N 가능한 출력이 있으며 7로 나눌 수 없습니다. (35 번 수행하면 35 ^ 7이 아닌 5 ^ 35가 있습니다.) 당신이 사용하는 많은 수의 호출을 균일하게하고 (그리고 숫자로도 가능하지만 7로 나눌 필요는 없습니다) IMHO는 rand ()에 대해 많은 수의 호출을 사용하는 대신 확률을 사용할 수 있습니다 상위 응답의 알고리즘으로, 정확한 균일 분포를 제공하고 rand ()에 대한 예상 호출 수가 적습니다.
ShreevatsaR

15
int ans = 0;
while (ans == 0) 
{
     for (int i=0; i<3; i++) 
     {
          while ((r = rand5()) == 3){};
          ans += (r < 3) >> i
     }
}

2
rand7 () 호출마다 rand5 ()에 대해 평균 30/7 = 4.29 호출을 수행하는 올바른 솔루션입니다.
Adam Rosenfield

3
요구가되게합니다 왼쪽 Shift : 작업에 대한 알고리즘ans += (r < 3) << i
woolfie

13

다음은 {1, 2, 3, 4, 5}에 균일 분포를 생성하는 난수 생성기를 사용하여 {1, 2, 3, 4, 5, 6, 7}에 균일 분포를 생성합니다. 코드가 지저분하지만 논리가 명확합니다.

public static int random_7(Random rg) {
    int returnValue = 0;
    while (returnValue == 0) {
        for (int i = 1; i <= 3; i++) {
            returnValue = (returnValue << 1) + SimulateFairCoin(rg);
        }
    }
    return returnValue;
}

private static int SimulateFairCoin(Random rg) {
    while (true) {
        int flipOne = random_5_mod_2(rg);
        int flipTwo = random_5_mod_2(rg);

        if (flipOne == 0 && flipTwo == 1) {
            return 0;
        }
        else if (flipOne == 1 && flipTwo == 0) {
            return 1;
        }
    }
}

private static int random_5_mod_2(Random rg) {
    return random_5(rg) % 2;
}

private static int random_5(Random rg) {
    return rg.Next(5) + 1;
}    

2
매우 효율적인 것은 아니지만 올바른 솔루션 (곡선보다 앞서 나갈 수 있음). 이것은 공정한 코인 플립 당 평균 25/6 = 4.17 호출, random_7 () 호출 당 random_5 () 호출의 총 평균 100/7 = 14.3 호출입니다.
Adam Rosenfield 3

다른 솔루션에 비해이 솔루션의 장점은 쉽게 확장되어 다른 균일하게 분포 된 범위를 생성 할 수 있다는 것입니다. 유효하지 않은 값 (8 개의 숫자를 생성하는 현재 솔루션의 0 값과 같은)을 다시 롤링하여 각 비트를 무작위로 선택하기 만하면됩니다.
DenTheMan

1
가능한 무한 루프 등
robermorales

1
@ robermorales : 매우 드 like니다.
Jason

13
int rand7() {
    int value = rand5()
              + rand5() * 2
              + rand5() * 3
              + rand5() * 4
              + rand5() * 5
              + rand5() * 6;
    return value%7;
}

선택한 솔루션과 달리 알고리즘은 일정한 시간에 실행됩니다. 그러나 선택한 솔루션의 평균 런타임보다 rand5를 2 번 더 호출합니다.

이 생성기는 완벽하지는 않지만 (0은 다른 숫자보다 확률이 0.0064 % 더 높습니다) 대부분의 실제 목적을 위해 일정 시간 보장은이 부정확성을 능가합니다.

설명

이 솔루션은 숫자 15,624를 7로 나눌 수 있다는 사실에서 파생됩니다. 따라서 0에서 15,624까지의 숫자를 무작위로 균일하게 생성 한 다음 mod 7을 취하면 거의 균일 한 rand7 생성기를 얻을 수 있습니다. 0에서 15,624까지의 숫자는 rand5를 6 번 롤링하고이를 사용하여 다음과 같이 기본 5 숫자의 숫자를 형성함으로써 균일하게 생성 될 수 있습니다.

rand5 * 5^5 + rand5 * 5^4 + rand5 * 5^3 + rand5 * 5^2 + rand5 * 5 + rand5

그러나 mod 7의 속성은 방정식을 약간 단순화 할 수있게합니다.

5^5 = 3 mod 7
5^4 = 2 mod 7
5^3 = 6 mod 7
5^2 = 4 mod 7
5^1 = 5 mod 7

그래서

rand5 * 5^5 + rand5 * 5^4 + rand5 * 5^3 + rand5 * 5^2 + rand5 * 5 + rand5

된다

rand5 * 3 + rand5 * 2 + rand5 * 6 + rand5 * 4 + rand5 * 5 + rand5

이론

숫자 15,624는 무작위로 선택되지 않았지만, fermat의 작은 정리를 사용하여 발견 할 수 있습니다. 이는 p가 소수이면

a^(p-1) = 1 mod p

이것은 우리에게

(5^6)-1 = 0 mod 7

(5 ^ 6) -1은 다음과 같습니다

4 * 5^5 + 4 * 5^4 + 4 * 5^3 + 4 * 5^2 + 4 * 5 + 4

이것은 기본 5 형식의 숫자이므로이 방법을 사용하여 임의의 난수 생성기에서 다른 임의의 난수 생성기로 이동할 수 있습니다. 지수 p-1을 사용할 때 항상 0에 대한 작은 바이어스가 발생합니다.

이 접근법을 일반화하고보다 정확하게하기 위해 다음과 같은 기능을 가질 수 있습니다.

def getRandomconverted(frm, to):
    s = 0
    for i in range(to):
        s += getRandomUniform(frm)*frm**i
    mx = 0
    for i in range(to):
        mx = (to-1)*frm**i 
    mx = int(mx/to)*to # maximum value till which we can take mod
    if s < mx:
        return s%to
    else:
        return getRandomconverted(frm, to)

1
이 발전기는 정확하지만 완전히 균일 하지는 않습니다 . 이를 확인하기 위해 [0,15624]의 균일 한 발전기에 15625 개의 가능한 결과가 있으며, 이는 7로 나눌 수 없다는 사실을 고려하십시오. 2232/15625). 결국 Fermat의 작은 정리를 사용하면 언뜻보기에는 정확 해 보일 수 있지만 (5 ^ 6) % 7 = 0이 아니라 (5 ^ 6) % 7 = 1이라고 말합니다. 후자는 5와 7이 모두 소수이므로 모든 지수에 대해 불가능합니다. 나는 그것이 여전히 허용 가능한 해결책이라고 생각하며 이것을 반영하기 위해 게시물을 편집했습니다.
비행가

12

숙제 문제가 허용됩니까?

이 함수는 "기본 5"수학을 수행하여 0과 6 사이의 숫자를 생성합니다.

function rnd7() {
    do {
        r1 = rnd5() - 1;
        do {
            r2=rnd5() - 1;
        } while (r2 > 1);
        result = r2 * 5 + r1;
    } while (result > 6);
    return result + 1;
}

3
매우 효율적인 것은 아니지만 올바른 솔루션 (곡선보다 앞서 나갈 수 있음). rnd7 ()을 호출 할 때마다 rnd5 ()를 평균 5 번 호출합니다.
Adam Rosenfield

좀 더 설명이 필요해 pls
Barry

1
@Barry-첫째, 두 개의 난수를 더할 수 없으며 선형 솔루션을 얻지 못합니다 (한 쌍의 주사위를 고려하십시오). 이제 "Base 5": 00, 01, 02, 03, 04, 10, 11을 고려하십시오. 이것은베이스 5에서 0-6입니다. 따라서 간단히베이스 5 숫자의 2 자리 숫자를 생성하고 추가 할 때까지 추가하면됩니다. 범위 내에있는 것을 얻으십시오. 이것이 r2 * 5 + r1이하는 일입니다. 우리는> 1의 높은 자리 싶지는 않을 것 때문에 R2는> 1 개 루프가
윌 Hartung 씨

이 솔루션은 균일 한 분포를 생성하지 않습니다. 숫자 1과 7은 한 가지 방법으로 만 생성 할 수 있지만 2-6은 각각 두 가지 방법으로 생성 할 수 있습니다. r1은 숫자 -1과 같고 r2는 0과 같거나 r1은 숫자 -2와 같고 r2는 같습니다. 1. 따라서 2-6은 평균 1 또는 7의 두 배로 반환됩니다.
Ted Hopp

12

가장 효율적인 답변을 제공하려는 추가 제약 조건, 즉 1-5 I의 길이로 균일하게 분포 된 정수의 입력 스트림, 가장 긴 길이의 1-7에서 균일하게 분포 된 정수로 m구성된 스트림 O을 고려하는 경우 에 mL(m).

이것을 분석하는 가장 간단한 방법은 스트림 I과 O5 진수 및 7 자리 숫자를 각각 처리하는 것입니다. 이것은 스트림을 취하고 stream a1, a2, a3,... -> a1+5*a2+5^2*a3+..과 유사하게 주요 답변의 아이디어에 의해 달성됩니다 O.

그럼 길이의 입력 스트림의 섹션 가지고 있으면 m choose n s.t. 5^m-7^n=c어디에 c>0가능한 한 작게한다. 그때부터 정수로 길이 m의 입력 스트림으로부터 균일 한지도가 15^m및 1의 정수에서 다른 균일 맵 7^n길이의 출력 스트림은 N 당사의 정수에 매핑 될 때 상기 입력 스트림에서 몇 가지 경우를 상실 할 수있는 위치 를 초과 7^n합니다.

그래서이 값주는 L(m)주위의 m (log5/log7)약이다 .82m.

위의 분석의 어려움은 5^m-7^n=c정확하게 풀기가 쉽지 않은 방정식 과 균일 한 값 15^m초과 7^n하여 효율성을 잃는 경우 입니다.

문제는 가능한 최상의 m (log5 / log7) 값에 얼마나 근접 할 수 있는지입니다. 예를 들어이 수가 정수에 가까워지면이 정확한 정수의 출력 값을 얻는 방법을 찾을 수 있습니까?

그렇다면 5^m-7^n=c입력 스트림에서 0~ 까지 균일 한 난수를 효과적으로 생성하고 (5^m)-1보다 큰 값을 사용하지 마십시오 7^n. 그러나 이러한 값은 구출되어 다시 사용할 수 있습니다. 그들은 1에서까지 균일 한 숫자 시퀀스를 효과적으로 생성합니다 5^m-7^n. 그런 다음이를 사용하여 더 많은 출력 값을 만들 수 있도록 7 진수로 변환 할 수 있습니다.

우리 가 size의 균일 한 입력으로부터 도출 된 정수 T7(X)의 출력 시퀀스의 평균 길이가되도록 하고 그것을 가정한다면 .random(1-7)X5^m=7^n0+7^n1+7^n2+...+7^nr+s, s<7

그런 다음 T7(5^m)=n0x7^n0/5^m + ((5^m-7^n0)/5^m) T7(5^m-7^n0)확률이 7 ^ n0 / 5 ^ m 인 확률이없는 길이의 시퀀스가 ​​없으므로 길이 5^m-7^n0가 남습니다 (5^m-7^n0)/5^m).

우리가 계속 대체하면 다음을 얻습니다.

T7(5^m) = n0x7^n0/5^m + n1x7^n1/5^m + ... + nrx7^nr/5^m  = (n0x7^n0 + n1x7^n1 + ... + nrx7^nr)/5^m

그 후

L(m)=T7(5^m)=(n0x7^n0 + n1x7^n1 + ... + nrx7^nr)/(7^n0+7^n1+7^n2+...+7^nr+s)

이것을 넣는 또 다른 방법은 다음과 같습니다.

If 5^m has 7-ary representation `a0+a1*7 + a2*7^2 + a3*7^3+...+ar*7^r
Then L(m) = (a1*7 + 2a2*7^2 + 3a3*7^3+...+rar*7^r)/(a0+a1*7 + a2*7^2 + a3*7^3+...+ar*7^r)

가장 좋은 경우는 어디 5^m=7^n+s에서 어디 에서 내 원래의 것 s<7입니다.

다음 T7(5^m) = nx(7^n)/(7^n+s) = n+o(1) = m (Log5/Log7)+o(1)과 같이.

최악의 경우는 k와 st 5 ^ m = kx7 + s 만 찾을 수있는 경우입니다.

Then T7(5^m) = 1x(k.7)/(k.7+s) = 1+o(1)

다른 경우는 그 사이에 있습니다. 우리가 매우 큰 m에 대해 얼마나 잘 할 수 있는지, 즉 오류 항을 얼마나 잘 얻을 수 있는지 보는 것이 흥미로울 것입니다.

T7(5^m) = m (Log5/Log7)+e(m)

e(m) = o(1)일반적 으로 달성하는 것은 불가능 해 보이지만 희망적으로 증명할 수 있습니다 e(m)=o(m).

그러면 모든 것은의 5^m다양한 값에 대한 7 자리 숫자의 분포에 달려 m있습니다.

나는 이것을 다루는 많은 이론이 있다고 확신한다. 나는 어느 시점에서보고하고보고 할 수있다.


+2 (가능한 경우)-이것이 유일한 대답이었습니다 (단순한 것이 아니라). 32 비트 정수에 맞는 두 번째 최상의 답변이 있습니다.
Rex Kerr

10

다음은 Adam 's answer의 작동하는 Python 구현입니다 .

import random

def rand5():
    return random.randint(1, 5)

def rand7():
    while True:
        r = 5 * (rand5() - 1) + rand5()
        #r is now uniformly random between 1 and 25
        if (r <= 21):
            break
    #result is now uniformly random between 1 and 7
    return r % 7 + 1

나는 파이썬으로보고있는 알고리즘을 던져서 그들과 놀 수 있기를 원합니다. 함께 던지기까지 오랜 시간이 걸리지 않았 으면 좋겠다는 희망으로 여기에 게시 할 것이라고 생각했습니다.


아니, 그건 내 대답과는 상당히 다릅니다. 21 번 반복하고 처음 20 개의 반복 결과를 버립니다. 또한 rand4 () 및 rand5 ()를 입력으로 사용하고 있으며, 이는 rand5 () 만 사용하는 규칙을 확실히 위반합니다. 마지막으로 불균일 분포를 생성합니다.
Adam Rosenfield

미안합니다. 이 질문을 살펴보면 너무 피곤해서 알고리즘을 완전히 읽지 못할 정도로 피곤했습니다. 나는 왜 당신이 21 번 루핑했는지 이해할 수 없기 때문에 파이썬으로 던졌습니다. 이제 훨씬 더 의미가 있습니다. 나는 random.randint (1, 4) 일을 속기로했지만 당신이 맞다고 생각합니다. 그것은 질문의 정신에 위배됩니다. 코드를 수정했습니다.
James McMahon

@robermorales-Adam Rosenfeld가 자신의 답변 에서 설명했듯이 [1, 7]에 대한 균일 한 분포를 제공하는 모든 솔루션에는 잠재적으로 무한한 일종의 수락 거부 루프가 포함됩니다. (그러나 rand5()괜찮은 PRNG 인 경우 루프는 무한대가 아니기 때문에 결국 5*(rand5() - 1) + rand5()<= 21이됩니다.)
Ted Hopp

10

왜 간단하지 않습니까?

int random7() {
  return random5() + (random5() % 3);
}

이 솔루션에서 1과 7을 얻을 확률은 모듈로 인해 낮습니다. 그러나 빠르고 읽기 쉬운 솔루션을 원한다면이 방법을 사용하십시오.


13
이것은 균일 한 분포를 생성하지 않습니다. 25 개의 가능한 결과를 모두 계산하여 확인할 수 있듯이 확률이 2/25, 4/25, 5/25, 5/25, 5/25, 3/25, 1/25 인 숫자 0-6을 생성합니다.
Adam Rosenfield

8

여기서 rand (n)이 " 0 에서 n-1 까지의 균일 한 분포에서 임의의 정수"를 의미 한다고 가정하면 , 여기에는 Python의 randint를 사용하는 코드 샘플이 있습니다. randint (7) 의 효과를 생성 하기 위해 randint (5) 및 상수 만 사용합니다 . 조금 어리석은 사실

from random import randint
sum = 7
while sum >= 7:
    first = randint(0,5)   
    toadd = 9999
    while toadd>1:
        toadd = randint(0,5)
    if toadd:
        sum = first+5
    else:
        sum = first

assert 7>sum>=0 
print sum

1
파이썬에는 없기 때문에 @robermorales do ... while. , 또는이거나 1보다 큰 숫자 1337일 수 있습니다 12345.
tckmn

8

Adam Rosenfield의 정답 뒤에는 다음과 같은 전제가 있습니다.

  • x = 5 ^ n (그의 경우 : n = 2)
  • 범위 [1, x] 내의 숫자 y 를 얻기 위해 nrand5 호출을 조작
  • z = ((int) (x / 7)) * 7
  • y> z이면 다시 시도하십시오. 그렇지 않으면 y % 7 + 1을 반환

n이 2 인 경우 y = {22, 23, 24, 25}와 같은 4 가지 버리기 가능성이 있습니다. n과 6을 함께 사용하면 1 회만 처리 할 수 ​​있습니다. y = {15625}.

5 ^ 6 = 15625
7 * 2232 = 15624

rand5를 더 많이 호출합니다. 그러나 버리기 값 (또는 무한 루프)을 얻을 가능성이 훨씬 낮습니다. y에 대해 가능한 버리기 값을 얻을 수있는 방법이 없다면 아직 찾지 못했습니다.


1
버리기 값이없는 경우는 없을 것입니다. 튀어 나오지 않은 경우 5 ^ n 및 7 ^ m에 공통 요소가 있습니다. 그러나 그것들은 (힘의 힘) 프라임이므로 그렇지 않습니다.
Rex Kerr

8

내 대답은 다음과 같습니다.

static struct rand_buffer {
  unsigned v, count;
} buf2, buf3;

void push (struct rand_buffer *buf, unsigned n, unsigned v)
{
  buf->v = buf->v * n + v;
  ++buf->count;
}

#define PUSH(n, v)  push (&buf##n, n, v)

int rand16 (void)
{
  int v = buf2.v & 0xf;
  buf2.v >>= 4;
  buf2.count -= 4;
  return v;
}

int rand9 (void)
{
  int v = buf3.v % 9;
  buf3.v /= 9;
  buf3.count -= 2;
  return v;
}

int rand7 (void)
{
  if (buf3.count >= 2) {
    int v = rand9 ();

    if (v < 7)
      return v % 7 + 1;

    PUSH (2, v - 7);
  }

  for (;;) {
    if (buf2.count >= 4) {
      int v = rand16 ();

      if (v < 14) {
        PUSH (2, v / 7);
        return v % 7 + 1;
      }

      PUSH (2, v - 14);
    }

    // Get a number between 0 & 25
    int v = 5 * (rand5 () - 1) + rand5 () - 1;

    if (v < 21) {
      PUSH (3, v / 7);
      return v % 7 + 1;
    }

    v -= 21;
    PUSH (2, v & 1);
    PUSH (2, v >> 1);
  }
}

다른 것보다 조금 더 복잡하지만 rand5에 대한 호출을 최소화한다고 생각합니다. 다른 솔루션과 마찬가지로 오랫동안 반복 될 가능성은 적습니다.


이것은 다른 솔루션과 크게 다르지 않지만 불필요하게 복잡하다는 추가 단점이 있습니다. 또한 숫자가 실제로 임의이면 부정확 한 비 결정적 루프-영구 가능성으로 인해 어려움을 겪습니다. 나는 여전히 약간 덜 균일 한 분포를 만들어내는 것 (아직도 충분하지는 않지만) 결정 론적 행동이 더 낫다고 생각합니다.
paxdiablo

@Pax : 이것이 불균일 한 분포를 만드는 방법에 대해 알려주십시오. 본인의 테스트뿐만 아니라 코드 분석을 통해 이것이 균일 한 분포를 생성 함을 나타냅니다. 이전에 논의했듯이 완벽하게 균일 한 분포를 생성하고 실행 시간의 상한을 일정하게 유지하는 것은 불가능합니다.
Adam Rosenfield


6

선택할 수있는 7 가지 가능성이없는 한 다른 난수를 그려서, 가능성의 수에 5를 곱하십시오. 펄에서 :

$num = 0;
$possibilities = 1;

sub rand7
{
  while( $possibilities < 7 )
  {
    $num = $num * 5 + int(rand(5));
    $possibilities *= 5;
  }
  my $result = $num % 7;
  $num = int( $num / 7 );
  $possibilities /= 7;
  return $result;
}

적어도 첫 번째 통화에서 분포가 균일하지 않습니다. 실제로, $possibilities루프를 종료하고 복귀하려면 항상 25로 커져야합니다. 따라서 첫 번째 결과는 입니다. (실제로 6 [0-124] % 7이므로) 균일하게 분포되지 않습니다 125 % 7 != 0.
bernard paulus

6

1부터 시작하는 범위가 마음에 들지 않으므로 0부터 시작합니다 :-)

unsigned rand5()
{
    return rand() % 5;
}

unsigned rand7()
{
    int r;

    do
    {
        r =         rand5();
        r = r * 5 + rand5();
        r = r * 5 + rand5();
        r = r * 5 + rand5();
        r = r * 5 + rand5();
        r = r * 5 + rand5();
    } while (r > 15623);

    return r / 2232;
}

이것은 승자입니다. 이렇게하면 7 개의 결과가 모두 같은 확률로 생성됩니다. from collections import defaultdict def r7(n): if not n: yield [] else: for i in range(1, 6): for j in r7(n-1): yield [i] + j def test_r7(): d = defaultdict(int) for x in r7(6): s = (((((((((x[5] * 5) + x[4]) * 5) + x[3]) * 5) + x[2]) * 5) + x[1]) * 5) + x[0] if s <= 15623: d[s % 7] += 1 print d
hughdbrown

5

거기서 균일 한 분배와 rand5 호출이 없습니다.

def rand7:
    seed += 1
    if seed >= 7:
        seed = 0
    yield seed

시드를 미리 설정해야합니다.


5

나는 그것이 대답되었다는 것을 알고 있지만 이것이 잘 작동하는 것 같지만 그것이 편견이 있는지 말할 수는 없습니다. 내 '테스트'는 그것이 합리적이라고 제안합니다.

아마도 Adam Rosenfield는 논평하기에 충분히 친절 할 것입니까?

내 (순진?) 아이디어는 다음과 같습니다.

rand7을 만들기에 충분한 임의의 비트가있을 때까지 rand5를 축적하십시오. 최대 2 개의 rand5가 필요합니다. rand7 숫자를 얻으려면 누적 값 mod 7을 사용하십시오.

누산기 오버플로를 피하기 위해 누산기가 mod 7이므로 누산기의 mod 7을 사용합니다.

(5a + rand5) % 7 = (k*7 + (5a%7) + rand5) % 7 = ( (5a%7) + rand5) % 7

rand7 () 함수는 다음과 같습니다.

(rand5의 범위를 0-4로하고 rand7도 마찬가지로 0-6입니다.)

int rand7(){
  static int    a=0;
  static int    e=0;
  int       r;
  a = a * 5 + rand5();
  e = e + 5;        // added 5/7ths of a rand7 number
  if ( e<7 ){
    a = a * 5 + rand5();
    e = e + 5;  // another 5/7ths
  }
  r = a % 7;
  e = e - 7;        // removed a rand7 number
  a = a % 7;
  return r;
}

편집 : 1 억 회에 대한 결과가 추가되었습니다.

'실제'랜드 기능 모드 5 또는 7

rand5 : 평균 = 1.999802 0 : 20003944 1 : 19999889 2 : 20003690 3 : 19996938 4 : 19995539 rand7 : 평균 = 3.000111 0 : 14282851 1 : 14282879 2 : 14284554 3 : 14288546 4 : 14292388 5 : 14288736 6 : 14280046

내 rand7

평균은 괜찮아 보이고 숫자 분포도 좋아 보입니다.

randt : avg = 3.000080 0 : 14288793 1 : 14280135 2 : 14287848 3 : 14285277 4 : 14286341 5 : 14278663 6 : 14292943


순차 상관 관계를보아야 할 것입니다. 나는 당신이 연속적인 쌍 (전임자와 짝을 이루는 각각의 "무작위"숫자)을 취하면 놀라운 것을 발견 할 수 있다고 생각합니다. 어떤 식 으로든 분포를 균일하게 유지해야하는 이유를 설명하지 않았습니다. 작업 프로그램은 일반적으로 왜 작동하는지에 대한 설명으로 시작해야합니다.
Ian

이러한 많은 솔루션에 순차적 상관 관계가 적용됩니까?
Philcolbourn

이러한 많은 솔루션에 순차적 상관 관계가 적용됩니까? 내가 이것을 시도한 이래 오랜 시간이 걸렸고 그것을 설명했다고 생각했습니다. 지금 살펴보면 rand5에서 풀에 임의의 비트를 누적하여 rand7 번호를 만들기에 충분히 철회하기 전에 누적 된 것을 확인하고 누적 장치를 오버플로하지 않도록합니다.
Philcolbourn

4

위에서 인용 한 우아한 알고리즘이 있지만 여기에는 접근하는 방법이 있지만 원형 교차로 일 수도 있습니다. 0에서 생성 된 값을 가정합니다.

R2 = 2보다 작은 값을 제공하는 난수 생성기 (샘플 공간 = {0, 1})
R8 = 8보다 작은 값을 제공하는 난수 생성기 (샘플 공간 = {0, 1, 2, 3, 4, 5, 6, 7) })

R2에서 R8을 생성하기 위해 R2를 세 번 실행하고 3 개의 모든 런의 결합 결과를 3 자리의 이진수로 사용합니다. R2가 3 번 실행될 때의 값 범위는 다음과 같습니다.

0 0-> 0
.
.
11 1-> 7

이제 R8에서 R7을 생성하려면 7을 반환하면 R7을 다시 실행하면됩니다.

int R7() {
  do {
    x = R8();
  } while (x > 6)
  return x;
}

로터리 솔루션은 R5에서 R2를 생성하는 것입니다 (R8에서 R7을 생성 한 것처럼), R2에서 R8, R8에서 R7을 생성하는 것입니다.


다른 여러 가지 방법과 마찬가지로이 방법은 R8에서 7의 긴 문자열을 얻을 수 있으므로 R7 호출 당 임의로 시간이 오래 걸릴 수 있습니다.
Alex North-Keys

4

다음은 정수에 완전히 맞고 최적의 약 4 % 내에있는 솔루션입니다 (예 : {0..6}의 모든 숫자에 대해 {0..4}의 1.26 난수 사용). 코드는 스칼라에 있지만 수학은 모든 언어로 명확해야합니다. 7 ^ 9 + 7 ^ 8이 5 ^ 11에 매우 가깝다는 사실을 이용하십시오. 따라서 기본 5에서 11 자리 숫자를 선택한 다음 범위 (9 기본 7 숫자 제공)에 있으면 기본 7에서 9 자리 숫자로 해석하거나 9 자리 숫자를 초과하면 8 자리 숫자로 해석하십시오. . :

abstract class RNG {
  def apply(): Int
}

class Random5 extends RNG {
  val rng = new scala.util.Random
  var count = 0
  def apply() = { count += 1 ; rng.nextInt(5) }
}

class FiveSevener(five: RNG) {
  val sevens = new Array[Int](9)
  var nsevens = 0
  val to9 = 40353607;
  val to8 = 5764801;
  val to7 = 823543;
  def loadSevens(value: Int, count: Int) {
    nsevens = 0;
    var remaining = value;
    while (nsevens < count) {
      sevens(nsevens) = remaining % 7
      remaining /= 7
      nsevens += 1
    }
  }
  def loadSevens {
    var fivepow11 = 0;
    var i=0
    while (i<11) { i+=1 ; fivepow11 = five() + fivepow11*5 }
    if (fivepow11 < to9) { loadSevens(fivepow11 , 9) ; return }
    fivepow11 -= to9
    if (fivepow11 < to8) { loadSevens(fivepow11 , 8) ; return }
    fivepow11 -= to8
    if (fivepow11 < 3*to7) loadSevens(fivepow11 % to7 , 7)
    else loadSevens
  }
  def apply() = {
    if (nsevens==0) loadSevens
    nsevens -= 1
    sevens(nsevens)
  }
}

테스트를 인터프리터 (실제로는 REPL)에 붙여 넣으면 다음과 같은 결과가 나타납니다.

scala> val five = new Random5
five: Random5 = Random5@e9c592

scala> val seven = new FiveSevener(five)
seven: FiveSevener = FiveSevener@143c423

scala> val counts = new Array[Int](7)
counts: Array[Int] = Array(0, 0, 0, 0, 0, 0, 0)

scala> var i=0 ; while (i < 100000000) { counts( seven() ) += 1 ; i += 1 }
i: Int = 100000000

scala> counts
res0: Array[Int] = Array(14280662, 14293012, 14281286, 14284836, 14287188,
14289332, 14283684)

scala> five.count
res1: Int = 125902876

분포는 근사하고 평평합니다 (대략 가우시안 분포에서 예상 한대로 각 빈에 10 ^ 8의 1/7의 약 10k 이내).


3

사용하여 압연 총 , 당신은 둘 다 할 수

  • 균등 한 분포를 유지; 과
  • 랜덤 시퀀스에서 어떤 요소도 희생하지 않아도됩니다.

이 두 가지 문제는 단순한 rand(5)+rand(5)...유형 솔루션 의 문제입니다 . 다음 파이썬 코드는 그것을 구현하는 방법을 보여줍니다 (이것은 대부분 배포를 증명합니다).

import random
x = []
for i in range (0,7):
    x.append (0)
t = 0
tt = 0
for i in range (0,700000):
    ########################################
    #####            qq.py             #####
    r = int (random.random () * 5)
    t = (t + r) % 7
    ########################################
    #####       qq_notsogood.py        #####
    #r = 20
    #while r > 6:
        #r =     int (random.random () * 5)
        #r = r + int (random.random () * 5)
    #t = r
    ########################################
    x[t] = x[t] + 1
    tt = tt + 1
high = x[0]
low = x[0]
for i in range (0,7):
    print "%d: %7d %.5f" % (i, x[i], 100.0 * x[i] / tt)
    if x[i] < low:
        low = x[i]
    if x[i] > high:
        high = x[i]
diff = high - low
print "Variation = %d (%.5f%%)" % (diff, 100.0 * diff / tt)

그리고이 결과는 다음과 같은 결과를 보여줍니다.

pax$ python qq.py
0:   99908 14.27257
1:  100029 14.28986
2:  100327 14.33243
3:  100395 14.34214
4:   99104 14.15771
5:   99829 14.26129
6:  100408 14.34400
Variation = 1304 (0.18629%)

pax$ python qq.py
0:   99547 14.22100
1:  100229 14.31843
2:  100078 14.29686
3:   99451 14.20729
4:  100284 14.32629
5:  100038 14.29114
6:  100373 14.33900
Variation = 922 (0.13171%)

pax$ python qq.py
0:  100481 14.35443
1:   99188 14.16971
2:  100284 14.32629
3:  100222 14.31743
4:   99960 14.28000
5:   99426 14.20371
6:  100439 14.34843
Variation = 1293 (0.18471%)

rand(5)+rand(5)이 값이 6을 초과하는 경우를 무시하는 단순한 방법은 위에 표시된 방법의 100 배인 18 %의 일반적인 변형을 갖습니다 .

pax$ python qq_notsogood.py
0:   31756 4.53657
1:   63304 9.04343
2:   95507 13.64386
3:  127825 18.26071
4:  158851 22.69300
5:  127567 18.22386
6:   95190 13.59857
Variation = 127095 (18.15643%)

pax$ python qq_notsogood.py
0:   31792 4.54171
1:   63637 9.09100
2:   95641 13.66300
3:  127627 18.23243
4:  158751 22.67871
5:  126782 18.11171
6:   95770 13.68143
Variation = 126959 (18.13700%)

pax$ python qq_notsogood.py
0:   31955 4.56500
1:   63485 9.06929
2:   94849 13.54986
3:  127737 18.24814
4:  159687 22.81243
5:  127391 18.19871
6:   94896 13.55657
Variation = 127732 (18.24743%)

그리고 Nixuz의 조언에 따라 스크립트를 정리하여 내용을 추출하고 사용할 수 있습니다 rand7....

import random

# rand5() returns 0 through 4 inclusive.

def rand5():
    return int (random.random () * 5)

# rand7() generator returns 0 through 6 inclusive (using rand5()).

def rand7():
    rand7ret = 0
    while True:
        rand7ret = (rand7ret + rand5()) % 7
        yield rand7ret

# Number of test runs.

count = 700000

# Work out distribution.

distrib = [0,0,0,0,0,0,0]
rgen =rand7()
for i in range (0,count):
    r = rgen.next()
    distrib[r] = distrib[r] + 1

# Print distributions and calculate variation.

high = distrib[0]
low = distrib[0]
for i in range (0,7):
    print "%d: %7d %.5f" % (i, distrib[i], 100.0 * distrib[i] / count)
    if distrib[i] < low:
        low = distrib[i]
    if distrib[i] > high:
        high = distrib[i]
diff = high - low
print "Variation = %d (%.5f%%)" % (diff, 100.0 * diff / count)

2
어, 그 말을 바꿔 보자. 시퀀스의 특정 지점에서 특정 x가 생성 된 경우 시퀀스의 다음 숫자에 대해 7 개 중 5 개만 생성 할 수 있습니다. 실제 RNG는 모든 샘플이 서로 독립적 일 수 있지만,이 경우 분명히 그렇지 않습니다.
Adam Rosenfield

3
원래 질문에 입력 및 출력 함수가 독립적이고 동일하게 분포 된 (iid) 샘플을 생성하는지 여부를 지정하지 않는 것이 사실이지만 입력 rand5 ()가 iid이면 출력 rand7 () 또한 iid 여야합니다. 그것이 합리적이지 않다고 생각되면 비 IID RNG를 사용하여 재미있게 보내십시오.
Adam Rosenfield

1
그래서, 대학의 수학자들이 한 말은 무엇입니까?
아담 로젠 필드

1
이 솔루션은 분명히 깨졌습니다. rand7을 호출 할 때마다 rand5 (평균)를 두 번 이상 호출해야하지만이 솔루션은 그렇지 않습니다. 따라서 무작위로 정의한 결과에 따라 결과가 무작위로 나올 수 없습니다.
Chris Suter

1
@Pax 함수를 반복 할 때마다 5-6 개의 값 중 하나만 반환 할 수 있습니다 (0-6 범위에 있음). 첫 번째 반복은 0-4 범위의 숫자 만 반환 할 수 있습니다. 따라서 함수가 균일 한 분포를 가질 수 있지만 샘플은 독립적이지 않습니다. 즉, 임의의 숫자 생성기에서 원하는 것이 아닌 상관 관계가 있습니다.
Chris Suter

3

이 답변은 Rand5 함수에서 가능한 가장 많은 엔트로피를 얻는 실험입니다. 따라서 t는 다른 구현보다 다소 불분명하고 거의 확실하게 느립니다.

0-4에서 균일 분포를 가정하고 0-6에서 균일 분포를 가정하면 :

public class SevenFromFive
{
  public SevenFromFive()
  {
    // this outputs a uniform ditribution but for some reason including it 
    // screws up the output distribution
    // open question Why?
    this.fifth = new ProbabilityCondensor(5, b => {});
    this.eigth = new ProbabilityCondensor(8, AddEntropy);
  } 

  private static Random r = new Random();
  private static uint Rand5()
  {
    return (uint)r.Next(0,5);
  }

  private class ProbabilityCondensor
  {
    private readonly int samples;
    private int counter;
    private int store;
    private readonly Action<bool> output;

    public ProbabilityCondensor(int chanceOfTrueReciprocal,
      Action<bool> output)
    {
      this.output = output;
      this.samples = chanceOfTrueReciprocal - 1;  
    }

    public void Add(bool bit)
    {
      this.counter++;
      if (bit)
        this.store++;   
      if (counter == samples)
      {
        bool? e;
        if (store == 0)
          e = false;
        else if (store == 1)
          e = true;
        else
          e = null;// discard for now       
        counter = 0;
        store = 0;
        if (e.HasValue)
          output(e.Value);
      }
    }
  }

  ulong buffer = 0;
  const ulong Mask = 7UL;
  int bitsAvail = 0;
  private readonly ProbabilityCondensor fifth;
  private readonly ProbabilityCondensor eigth;

  private void AddEntropy(bool bit)
  {
    buffer <<= 1;
    if (bit)
      buffer |= 1;      
    bitsAvail++;
  }

  private void AddTwoBitsEntropy(uint u)
  {
    buffer <<= 2;
    buffer |= (u & 3UL);    
    bitsAvail += 2;
  }

  public uint Rand7()
  {
    uint selection;   
    do
    {
      while (bitsAvail < 3)
      {
        var x = Rand5();
        if (x < 4)
        {
          // put the two low order bits straight in
          AddTwoBitsEntropy(x);
          fifth.Add(false);
        }
        else
        { 
          fifth.Add(true);
        }
      }
      // read 3 bits
      selection = (uint)((buffer & Mask));
      bitsAvail -= 3;     
      buffer >>= 3;
      if (selection == 7)
        eigth.Add(true);
      else
        eigth.Add(false);
    }
    while (selection == 7);   
    return selection;
  }
}

Rand5에 대한 호출 당 버퍼에 추가 된 비트 수는 현재 4/5 * 2이므로 1.6입니다. 1/5 확률 값이 포함되어 있으면 0.05만큼 증가하므로 1.65이지만 이것을 비활성화 해야하는 코드의 주석을 참조하십시오.

Rand7 호출에 소비 된 비트 = 3 + 1/8 * (3 + 1/8 * (3 + 1/8 * (...
이것은 3 + 3/8 + 3/64 + 3/512 ...) 약 3.42

7 개에서 정보를 추출하여 호출 당 1 / 8 * 1 / 7 비트를 회수하므로 약 0.018

이는 통화 당 3.4 비트의 순 소비량을 제공하며, 이는 Rand7마다 Rand5에 대한 2.125 호출 비율을 의미합니다. 최적은 2.1이어야합니다.

Rand5에 대한 호출 비용이 매우 비싸지 않은 한 (예 : 외부 엔트로피 소스를 호출하는 경우) 이 방법이 다른 많은 방법 보다 훨씬 느리다고 생각합니다 .


"if (count> 1)"은 "if (count <= 1)"이어야하고, 그 뒤에 나오는 "i ++"는 그 앞에있는 중괄호 안에 있어야합니다. BitsSet ()이 올바른지 확실하지 않지만 다소 관련이 없습니다.
Adam Rosenfield

그러나 전반적으로 함수를 이해하기가 매우 어렵습니다. 그것은 만드는가 약간 더 합병증의 비용으로, 그것은 그렇지 않으면 수보다 엔트로피를보다 효율적으로 사용. 3이 충분할 때 첫 번째 호출에서 처음에 35 개의 임의 비트로 버퍼를 채울 이유가 없습니다.
Adam Rosenfield

<= 감사를 수정했습니다 .i ++은 실제로 있어야합니다. 0과 1의 경우에 발생해야합니다 (버퍼에 각각 1 또는 0을 추가). 이것은 내가 사용하는 것이 절대적으로 아닙니다. 엄청나게 복잡합니다. 나는 단지 문제에 내재 된 이론적 엔트로피 한계에 얼마나 근접 할 수 있는지에 관심이 있었다. 피드백에 감사드립니다. 아이러니하게도 첫 번째 호출에서 버퍼를 채우는 것이 더 간단 해졌습니다. :)
ShuggyCoUk

나는 이것을 이해하기 쉽도록 (속도를 희생하여) 재 작업했지만 올바르게 만들었습니다. 1/5 비트가 개수가 균일하더라도 문제를 일으키는 이유는 무엇입니까?
ShuggyCoUk

3

PHP에서

function rand1to7() {
    do {
        $output_value = 0;
        for ($i = 0; $i < 28; $i++) {
            $output_value += rand1to5();
        }
    while ($output_value != 140);
    $output_value -= 12;
    return floor($output_value / 16);
}

루프는 16에서 127 사이의 임의의 숫자를 생성하고 16에서 16으로 나누어 1과 7.9375 사이의 부동 소수점을 생성 한 다음 1과 7 사이의 정수를 얻기 위해 반올림합니다. 실수하지 않으면 16/112 확률이 있습니다. 7 가지 결과 중 하나


조건부 루프를 사용하지 않고 바닥 대신 모듈로를 사용하면 이와 비슷한 대답이 더 쉽습니다. 난 그냥 숫자를 지금 당장 수 없습니다.
dqhendricks

3
extern int r5();

int r7() {
    return ((r5() & 0x01) << 2 ) | ((r5() & 0x01) << 1 ) | (r5() & 0x01);
}

문제 : 0-6이 아닌 0-7 범위에서 불균일하게 반환됩니다. 사실, 당신은 할 수 7 = 111bp(7) = 8 / 125
폴 러스 버나드

3

나는 @Adam Rosenfield와 같은 정확한 솔루션을 제공 하지만 무한 루프 문제 는 없으며 다른 하나는 거의 완벽한 솔루션이지만 첫 번째 솔루션보다 빠른 구현을 제공하는 4 가지 답변이 있다고 생각 합니다.

가장 정확한 솔루션은에 대한 7 번의 호출이 필요 rand5하지만 이해하기 위해 계속 진행할 수 있습니다.

방법 1-정확한

Adam의 대답의 강점은 완벽한 균일 분포를 제공하며 rand5 ()에 대한 두 번의 호출 만 필요하다는 가능성이 매우 높다는 것입니다 (21/25). 그러나 최악의 경우는 무한 루프입니다.

아래의 첫 번째 솔루션은 완벽한 균일 분포를 제공하지만 총 42 번의 호출이 필요합니다 rand5. 무한 루프가 없습니다.

다음은 R 구현입니다.

rand5 <- function() sample(1:5,1)

rand7 <- function()  (sum(sapply(0:6, function(i) i + rand5() + rand5()*2 + rand5()*3 + rand5()*4 + rand5()*5 + rand5()*6)) %% 7) + 1

R에 익숙하지 않은 사람들을 위해 간단한 버전이 있습니다.

rand7 = function(){
  r = 0 
  for(i in 0:6){
    r = r + i + rand5() + rand5()*2 + rand5()*3 + rand5()*4 + rand5()*5 + rand5()*6
  }
  return r %% 7 + 1
}

의 배포는 rand5유지됩니다. 수학을 수행하면 루프의 7 개 반복마다 5 ^ 6 개의 가능한 조합이 있으므로 가능한 총 조합 수는 (7 * 5^6) %% 7 = 0입니다. 따라서 우리는 7의 동일한 그룹으로 생성 된 난수를 나눌 수 있습니다. 이에 대한 자세한 내용은 방법 2를 참조하십시오.

가능한 모든 조합은 다음과 같습니다.

table(apply(expand.grid(c(outer(1:5,0:6,"+")),(1:5)*2,(1:5)*3,(1:5)*4,(1:5)*5,(1:5)*6),1,sum) %% 7 + 1)

    1     2     3     4     5     6     7 
15625 15625 15625 15625 15625 15625 15625 

Adam의 방법이 훨씬 빠르게 실행될 것임을 보여주는 것이 당연하다고 생각합니다. rand5Adam의 솔루션에서 42 개 이상의 호출이있을 확률 은 매우 작습니다 ( (4/25)^21 ~ 10^(-17)).

방법 2-정확하지 않음

이제 두 번째 방법은 거의 균일하지만 6 번의 호출이 필요합니다 rand5.

rand7 <- function() (sum(sapply(1:6,function(i) i*rand5())) %% 7) + 1

다음은 간단한 버전입니다.

rand7 = function(){
  r = 0 
  for(i in 1:6){
    r = r + i*rand5()
  }
  return r %% 7 + 1
}

이것은 본질적으로 방법 1의 한 번의 반복입니다. 가능한 모든 조합을 생성하는 경우 결과 카운트는 다음과 같습니다.

table(apply(expand.grid(1:5,(1:5)*2,(1:5)*3,(1:5)*4,(1:5)*5,(1:5)*6),1,sum) %% 7 + 1)

   1    2    3    4    5    6    7 
2233 2232 2232 2232 2232 2232 2232

5^6 = 15625시험판 에는 하나의 숫자가 한 번 더 나타납니다 .

이제 방법 1에서 1-6을 더하여 숫자 2233을 각 연속 지점으로 이동합니다. 따라서 총 조합 수가 일치합니다. 이것은 5 ^ 6 %% 7 = 1이기 때문에 작동하며, 7 개의 적절한 변형을 수행하므로 (7 * 5 ^ 6 %% 7 = 0).

방법 3-정확

방법 1과 2의 인수가 이해되면, 방법 3이 따르고 7 개의 호출 만 필요합니다 rand5. 이 시점에서 이것이 정확한 솔루션에 필요한 최소 통화 수라고 생각합니다.

다음은 R 구현입니다.

rand5 <- function() sample(1:5,1)

rand7 <- function()  (sum(sapply(1:7, function(i) i * rand5())) %% 7) + 1

R에 익숙하지 않은 사람들을 위해 간단한 버전이 있습니다.

rand7 = function(){
  r = 0 
  for(i in 1:7){
    r = r + i * rand5()
  }
  return r %% 7 + 1
}

의 배포는 rand5유지됩니다. 수학을 수행하면 루프의 7 개 반복 각각에 5 개의 가능한 결과가 있으므로 가능한 총 조합 수는 (7 * 5) %% 7 = 0입니다. 따라서 동일한 그룹 7에서 생성 된 난수를 나눌 수 있습니다. 이에 대한 자세한 내용은 방법 1과 2를 참조하십시오.

가능한 모든 조합은 다음과 같습니다.

table(apply(expand.grid(0:6,(1:5)),1,sum) %% 7 + 1)

1 2 3 4 5 6 7  
5 5 5 5 5 5 5 

나는 아담의 방법이 여전히 더 빨리 실행될 것이라는 것을 보여주는 것이 당연하다고 생각합니다. rand5Adam의 솔루션에서 7 번 이상 호출 할 가능성 은 여전히 ​​작습니다 ( (4/25)^3 ~ 0.004).

방법 4-정확하지 않음

이것은 두 번째 방법의 작은 변형입니다. 거의 균일하지만 7 rand5번의 호출이 필요합니다 .

rand7 <- function() (rand5() + sum(sapply(1:6,function(i) i*rand5())) %% 7) + 1

다음은 간단한 버전입니다.

rand7 = function(){
  r = 0 
  for(i in 1:6){
    r = r + i*rand5()
  }
  return (r+rand5()) %% 7 + 1
}

가능한 모든 조합을 생성하면 다음과 같은 결과가 나타납니다.

table(apply(expand.grid(1:5,(1:5)*2,(1:5)*3,(1:5)*4,(1:5)*5,(1:5)*6,1:5),1,sum) %% 7 + 1)

    1     2     3     4     5     6     7 
11160 11161 11161 11161 11161 11161 11160

5^7 = 78125시험 에서는 두 개의 숫자가 한 번 덜 나타납니다 . 대부분의 경우, 나는 그걸로 살 수 있습니다.


1
나는 R에 익숙하지 않지만, 어떻게 작동하는지 오해하지 않는 한 방법 1은 정확하지 않습니다. (5 ^ 6) * 7이 아니라 (5 ^ 6) ^ 7 = 5 ^ 42 개의 가능한 결과를 갖습니다. 5 ^ 42는 7로 나눌 수 없습니다. 마찬가지로 방법 3도 정확하지 않습니다. 5 * 7이 아니라 5 ^ 7 개의 가능한 결과가 있습니다. ( i=7추가 7*rand5()하면 모드 7 r의 값이 변경되지 않으므로 방법 3의 마지막 루프 반복 은 아무런 영향 을 미치지 않습니다 r.)
Adam Rosenfield

2

필요한 함수는 rand1_7 () 이며, rand1_5 ()을 작성하여 테스트하고 플로팅 할 수 있습니다.

import numpy
def rand1_5():
    return numpy.random.randint(5)+1

def rand1_7():
    q = 0
    for i in xrange(7):  q+= rand1_5()
    return q%7 + 1
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.