문제

좋아, 이것은 지금 몇 년 동안 나를 괴롭혔다. 학교에서 통계와 더 높은 수학을 빨아 들으면 돌아가십시오. 지금. 너무 늦었 어.

괜찮아. 심호흡을하십시오. 규칙은 다음과 같습니다. 가져가다 30 편 주사위 (예, 그들은 존재합니다)) 동시에 굴립니다.

  • 두 숫자를 추가하십시오
  • 두 주사위 모두 <= 5 또는> = 26을 보이면 다시 던지고 추가하다 당신이 가진 것에 대한 결과
  • 하나는 <= 5이고 다른 하나는> = 26이면 다시 던지고 덜다 당신이 가진 것의 결과
  • > 5와 <26이 될 때까지 반복하십시오!

코드를 작성하는 경우 (아래 참조) 주사위를 몇 백만 번 굴리면 최종 결과로 각 숫자를 얼마나 자주받는 지 계산하면 1 사이에 약 45 °, 약 45 ° °의 곡선이 1과 1의 평평한 곡선을 얻습니다. 60 이상으로 60 이상.

이제 질문 : 프로그램을 작성할 수 있습니까? 계산하다 그만큼 정확한 값 f (x), 즉 특정 값을 굴릴 확률?

배경 : 우리의 롤 플레잉 게임 "Jungle of Stars"를 위해 우리는 임의의 이벤트를 확인하는 방법을 찾았습니다. 위의 규칙은 당신이 시도한 것에 대한 훨씬 더 안정적인 결과를 보장합니다 :)

주변 괴짜의 경우 파이썬의 코드 :

import random
import sys

def OW60 ():
    """Do an open throw with a "60" sided dice"""
    val = 0
    sign = 1

    while 1:
        r1 = random.randint (1, 30)
        r2 = random.randint (1, 30)

        #print r1,r2
        val = val + sign * (r1 + r2)
        islow = 0
        ishigh = 0
        if r1 <= 5:
            islow += 1
        elif r1 >= 26:
            ishigh += 1
        if r2 <= 5:
            islow += 1
        elif r2 >= 26:
            ishigh += 1

        if islow == 2 or ishigh == 2:
            sign = 1
        elif islow == 1 and ishigh == 1:
            sign = -1
        else:
            break

        #print sign

    #print val
    return val

result = [0] * 2000
N = 100000
for i in range(N):
    r = OW60()
    x = r+1000
    if x < 0:
        print "Too low:",r
    if i % 1000 == 0:
        sys.stderr.write('%d\n' % i)
    result[x] += 1

i = 0
while result[i] == 0:
    i += 1

j = len(result) - 1
while result[j] == 0:
    j -= 1

pSum = 0
# Lower Probability: The probability to throw this or less
# Higher Probability: The probability to throw this or higher
print "Result;Absolut Count;Probability;Lower Probability;Rel. Lower Probability;Higher Probability;Rel. Higher Probability;"
while i <= j:
    pSum += result[i]
    print '%d;%d;%.10f;%d;%.10f;%d;%.10f' % (i-1000, result[i], (float(result[i])/N), pSum, (float(pSum)/N), N-pSum, (float(N-pSum)/N))
    i += 1
도움이 되었습니까?

해결책

이해하기 전에 먼저 코드를 다시 작성해야했습니다.

def OW60(sign=1):
    r1 = random.randint (1, 30)
    r2 = random.randint (1, 30)
    val = sign * (r1 + r2)

    islow  = (r1<=5)  + (r2<=5)
    ishigh = (r1>=26) + (r2>=26)

    if islow == 2 or ishigh == 2:
        return val + OW60(1)
    elif islow == 1 and ishigh == 1:
        return val + OW60(-1)
    else:
        return val

어쩌면 당신은 이것을 덜 읽기 쉽다는 것을 알 수 있습니다. 모르겠어요. (코드에서 "결과"를 사용하는 방식에 대해서도 Python의 사용 방법에 대해서도 생각하는 것과 동등한 지 확인하십시오.) DITT에스?

어쨌든, 프로그래밍 스타일의 문제는 제쳐두고 : f (x)가 CDF OW60 (1), 즉

F(x) = the probability that OW60(1) returns a value ≤ x.

마찬가지로

G(x) = the probability that OW60(-1) returns a value ≤ x.

그런 다음 첫 번째 던지기 결과의 모든 (30 × 30) 가능한 값을 합산하여 정의에서 f (x)를 계산할 수 있습니다. 예를 들어, 첫 번째 던지기가 (2,3) 인 경우 다시 굴러 가기 때문에이 용어는 (1/30) (1/30) (5+F (x-5)) F (F) 표현식에 기여합니다. 엑스). 그래서 당신은 외설적으로 긴 표현을 얻을 수 있습니다

F(x) = (1/900)(2+F(x-2) + 3+F(x-3) + ... + 59+F(x-59) + 60+F(x-60))

이는 [30] × [30]의 각 쌍 (a, b)마다 900 개 이상의 항 (A, B)입니다. ≤ 5 또는 둘 다 ≥26 인 쌍 (A, B)은 A+B+F (XAB)라는 용어를 가지며, 1 ≤5 및 1 ≥26의 쌍은 A+B+G (XAB)라는 용어를 갖고 있으며, 나머지는 다시 던지지 않기 때문에 (a+b)와 같은 용어가 있습니다.

마찬가지로 당신은 가지고 있습니다

G(x) = (1/900)(-2+F(x-2) + (-3)+F(x-3) + ... + (-59)+F(x-59) + (-60)+F(x-60))

물론 계수를 수집 할 수 있습니다. 발생하는 유일한 F 항은 F (X-60)에서 F (X-52) 및 F (X-10)에서 F (X-2)까지 (A, B≥26 또는 둘 다 5) 및 발생하는 유일한 G 항은 g (x-35)에서 G (x-27)까지 (a, b ≥26 및 다른 ≤5의 경우)이므로 30 항보다 적은 용어가 적습니다. 어쨌든 벡터 v (x)를 다음과 같이 정의합니다.

V(x) = [F(x-60) G(x-60) ... F(x-2) G(x-2) F(x-1) G(x-1) F(x) G(x)]

(예 : F 및 G에 대한 표현에서) 형식의 관계가 있습니다.

V(x) = A*V(x-1) + B

적절한 행렬 A와 적절한 벡터 B (계산할 수있는 적절한 벡터 B)의 경우 x 형식의 초기 값에서 시작하여 x의 경우 x)에서 충분히 작게 시작하면 f (x) 및 g (x)를 찾을 수 있습니다. ) 범위의 x의 경우 임의로 정밀도를 임의로 가깝게하려고합니다. (그리고 x를 던질 확률 인 f (x)는 단지 f (x) -f (x-1)이므로 나옵니다.)

더 나은 방법이있을 수 있습니다. 그래도 모든 것이 말하고 끝났습니다. 왜 이렇게하고 있습니까? 원하는 분포가 무엇이든, 적절한 매개 변수를 갖춘 멋지고 간단한 확률 분포가 있으며, 좋은 특성이 있습니다 (예 : 작은 분산, 단면 오류 등). 임의의 숫자를 생성하기 위해 자신의 임시 절차를 구성 할 이유가 없습니다.

다른 팁

나는 2 천만 던지기 샘플에 대한 몇 가지 기본 통계를 수행했습니다. 결과는 다음과 같습니다.

Median: 17 (+18, -?) # This result is meaningless
Arithmetic Mean: 31.0 (±0.1)
Standard Deviation: 21 (+1, -2)
Root Mean Square: 35.4 (±0.7)
Mode: 36 (seemingly accurate)

오류는 실험적으로 결정되었다. 산술 평균과 모드는 실제로 정확하며 매개 변수를 매우 적극적으로 바꾸는 것은 그다지 영향을 미치지 않는 것 같습니다. 중앙값의 행동이 이미 설명되었다고 생각합니다.

참고 : 함수에 대한 적절한 수학적 설명을 위해이 숫자를 취하지 마십시오. 그것들을 사용하여 분포의 모습을 빠르게 얻으십시오. 다른 것에 대해, 그들은 정확하지 않더라도 충분히 정확하지 않습니다.

아마도 이것은 누군가에게 도움이 될 것입니다.

편집 2 :

graph

991 값을 기준으로합니다. 나는 그것에 더 많은 가치를 ram 다 할 수 있었지만 결과를 왜곡했을 것입니다. 이 샘플은 상당히 일반적입니다.

편집 1 :

비교를 위해 60면 다이에 대한 위의 값은 다음과 같습니다.

Median: 30.5
Arithmetic Mean: 30.5
Standard Deviation: 7.68114574787
Root Mean Square: 35.0737318611

이 값은 실험이 아닌 계산됩니다.

화합물의 무한 확률은 ... 사소한 일입니다. 나는 James Curran과 같은 방식으로 문제를 해결하려고했지만 소스 코드에서 세 번째 롤 세트가있을 수 있음을 알았습니다. 문제는 해결할 수 있지만 대부분의 다이 롤링 시뮬레이터를 훨씬 뛰어 넘습니다.

1-60 정도의 복잡한 곡선으로 -inf에서 +inf까지 임의의 범위가 필요한 특별한 이유가 있습니까? 2D30의 벨 곡선이 허용되지 않는 이유는 무엇입니까? 요구 사항을 설명하면 누군가가 더 간단하고 경계 알고리즘을 제공 할 수 있습니다.

어디 한번 보자. 그만큼 던지기 (때때로 첫 번째 롤에 추가되거나 빼기)에는 31에 쉽게 예측 가능한 벨 커브가 있습니다. 물론 첫 번째 롤은 문제입니다.

첫 번째 롤의 경우 900 개의 가능한 조합이 있습니다.

  • 50 조합으로 인해 두 번째 롤이 추가됩니다.
  • 25 조합으로 인해 두 번째 롤을 빼냅니다.
  • 두 번째 롤의 벨 곡선과 일치하는 825 조합을 남겨 둡니다.

빼기 세트 (사전 세포화)는 범위 (27..35)에서 벨 곡선을 형성합니다. 추가 세트의 하단 절반은 범위 (2..10)에서 벨 곡선을 형성하는 반면 상단 절반은 범위 (52 ... 60)의 벨 곡선을 형성합니다.

내 프로블은 약간 녹슬으므로 정확한 값을 알 수는 없지만 이로 인해 예측 가능한 값이 이루어지는 것이 분명해야합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top