2010-04-21 7 views
4

변화하는 수의 6면 다이 롤의 확률 분포를 계산하려고합니다. 예를 들어, 다음과 같이 3D6은 3 내지 18의 범위 :6 면체 주사위로 확률 분포 계산

function distributionCalc($numberDice,$sides=6) { 
for ($i=0; $i<pow($sides,$numberDice); $i++) 
    { 
    $sum=0; 
    for ($j=0; $j<$numberDice; $j++) 
     { $sum+=(1+(floor($i/pow($sides,$j))) % $sides); } 
    $distribution[$sum]++; 
    } 
return $distribution; 
} 

용 루프 내측 $의 J는 바닥 마법을 사용하여 그것을 계산이 PHP 프로그램을 작성

3:1, 4:3, 5:6, 6:10, 7:15, 8:21, 9:25, 10:27, 11:27, 12:25, 13:21, 14:15, 15:10, 16:6, 17:3, 18:1 

주사위의 개수 인 숫자의 개수와베이스 -6- 계산 시퀀스를 생성하는 계수 함수이므로 3D6는 회수는 :

111,112,113,114,115,116,121,122,123,124,125,126,131,etc. 

함수는 각각의 합계를 취하므로, 3,4,5,6,7,8,4,5,6,7,8,9,5 등으로 읽습니다. 6^3 개의 가능한 결과를 모두 거쳐 3과 18 사이의 $ 분배 배열에있는 해당 슬롯에 1을 더합니다. 매우 직설적입니다. 그러나 그것은 약 8d6까지만 작동하며, 이후 수십억 개의 계산을 수행하기 때문에 서버 시간 초과가 발생합니다.

그러나 나는 확률이 감미로운 종 곡선 분포를 따르기 때문에 필요하지 않다고 생각합니다. 숫자를 건너 뛰고 커브 자체로 곧바로 갈 수있는 방법이 있는지 궁금합니다. 예를 들어, 80d6 (범위 : 80-480)과 같이이를 수행 할 수있는 방법이 있습니까? 6^80 계산을하지 않고도 분포를 투사 할 수 있습니까?

나는 전문 코더가 아니며 확률은 여전히 ​​나에게 새로운 것이므로 모든 도움에 감사드립니다!

스티븐

답변

1

당신은 좋아 Binomial Distribution

+0

이항 분포는 다이 롤의 * sum *을 모델링 할 수 없으며 개별 결과 만 표시합니다 (예 : 40 개의 주사위를 굴릴 경우 몇 개의 롤이 나올지) – rlbond

1

을 찾고, 그래서 하나의 다이 롤링 시작하자된다. 우리는 평균이 3.5임을 압니다.

sum(p(x) * (x - M)^2) (M은 평균, x는 주사위 결과, p는 주사위 결과의 확률 임)도 계산할 수 있습니다.

이 공식을 사용하면 단일 주사위 롤의 분산은 35/12 = 1/6 * ((- 2.5)^2 + (-1.5)^2 + (-0.5)^2 + 0.5^2 + 1.5^2 + 2.5^2)

동일한 분포의 여러 독립 샘플의 경우에도 분산이 더해집니다. 따라서 N 개의 주사위를 굴리면 평균 3.5 * N 및 분산 35 * N/12의 새로운 분포를 얻게됩니다.

따라서 평균 3.5 * N 및 분산 35 * N/12의 정규 분포를 생성하면 적절한 주사위 수를 굴린다고 가정 할 때 매우 적합합니다. PERL에서

3

:

#! 
my($DieType, $NumDice, $Loaded) = @ARGV; 

my $subname = "D" . $DieType . (($Loaded eq "Loaded") ? "Loaded" : "Normal"); 
my $Prob = \&$subname; 

my $width = 12; 
my $precision = $width - 2; 

printf "%5s %-${width}s \n", "Pip:", "Frequency:"; 
for (my $j = $NumDice; $j <= $DieType * $NumDice ; $j++) { 
    printf "%5d %${width}.${precision}f \n", $j, Frequency($DieType, $NumDice, $j); 
} 

sub D6Normal { 
    my $retval = 1/6; 
} 

sub D6Loaded { 
    my $retval = 1/6; 

    CASE: for ($_[0]) { 
    /1/ && do { $retval -= 0.02/6; last CASE; }; 
    /2..5/ && do { $retval += 0.0025/6; last CASE; }; 
    /6/ && do { $retval += 0.01/6; last CASE; }; 
    } 
    return $retval; 
} 

sub D8Normal { 
    my $retval = 1/8; 
} 

sub D10Normal { 
    my $retval = 1/10; 
} 

sub D10Loaded { 
    my $retval = 1/10; 

    CASE: for ($_[0]) { 
    /1..8/ && do { last CASE; }; 
    /9/ && do { $retval -= 0.01/10; last CASE; }; 
    /10/ && do { $retval += 0.01/10; last CASE; }; 
    } 
    return $retval; 
} 

sub D12Normal { 
    my $retval = 1/12; 
} 

sub D20Normal { 
    my $retval = 1/20; 
} 

sub D32Normal { 
    my $retval = 1/32; 
} 

sub D100Normal { 
    my $retval = 1/100; 
} 

sub Frequency { 
    my($DieType, $NumberofDice, $PipCount) = @_; 

    if (($PipCount > ($DieType * $NumberofDice)) || ($PipCount < $NumberofDice)) { 
    return 0; 
    } 

    if (! exists $Freq{$NumberofDice}{$PipCount}) { 
    if ($NumberofDice > 1) { 
     for (my $i = max(1, $PipCount - $DieType); $i <= min($DieType * ($NumberofDice - 1), $PipCount - 1); $i++) { 
     $Freq{$NumberofDice}{$PipCount} += &$Prob($PipCount - $i) * Frequency($DieType, $NumberofDice - 1, $i); 
     } 
    } else { 
     $Freq{$NumberofDice}{$PipCount} = &$Prob($PipCount); 
    } 
    } 
    return $Freq{$NumberofDice}{$PipCount}; 
} 

sub max { 
    my $max = shift(@_); 
    foreach my $arg (@_) { 
    $max = $arg if $max < $arg; 
    } 
    return $max; 
} 

sub min { 
    my $min = shift(@_); 
    foreach my $arg (@_) { 
    $min = $arg if $min > $arg; 
    } 
    return $min; 
} 
+0

코드에 대한 설명이 사용자의 대답을 읽는 데 도움이됩니다. –

0

재정 수를 생략하고 곡선 자체로 바로 갈 수있는 방법이 있는지 궁금 해요. 예를 들어, 80d6 (범위 : 80-480)과 같이이를 수행 할 수있는 방법이 있습니까? 6^80 계산을하지 않고도 분포를 투사 할 수 있습니까?

예. 독립 변수의 합계의 확률 함수는 각 변수의 확률 함수의 회선입니다.

이 경우의 회선은 단지 특별한 합계입니다. (더 일반적으로, 컨볼 루션은 정수입니다.) p와 q를 두 개의 이산 확률 함수라고합시다. 컨볼 루션은 일반적으로 별표로 표시됩니다. i가 1 (+ n_p n_q - 1)의 범위

(p * q)[i] = sum_{j=1}^(n_p) p[j] q[i - j + 1] 

n_p으로는 P의 요소의 개수 및 Q의 요소 수를 n_q. (i - j + 1)이 1보다 작거나 n_q보다 큰 경우, q [i - j + 1]을 0으로 두십시오 (따라서이 용어들은 합계에서 사라집니다).

손에있는 경우, p = q = [1/6, 1/6, 1/6, 1/6, 1/6, 1/6], n_p = n_q = 6입니다. 3 롤의 합계의 (p * p * p)이다. 80 롤의 합계 분포는 (p * p * p * ... (76 more p 's) ... * p)입니다.

PHP를 잘 모르므로 Maxima에 약간의 프로그램을 작성했습니다.

discrete_conv (p, q) := makelist (discrete_conv1 (p, q, i), i, 1, length (p) + length (q) - 1); 
discrete_conv1 (p, q, i) := sum (p [j] * foo (q, i - j + 1), j, 1, length (p)); 
foo (a, i) := if 1 <= i and i <= length (a) then a [i] else 0; 
r : [1/6, 1/6, 1/6, 1/6, 1/6, 1/6]; 
discrete_conv (r, discrete_conv (r, r)); 
=> [1/216,1/72,1/36,5/108,5/72,7/72,25/216,1/8,1/8,25/216,7/72, 
    5/72,5/108,1/36,1/72,1/216] 

discrete_conv를 계속 반복하면 숫자가 점점 더 정상적인 분포가되도록해야합니다. 이것은 중심 극한 정리의 실례입니다.

색인 생성과 관련하여 실수를 한 것으로 완전히 확인할 수 있습니다. 희망이 문제에 대한 약간의 조명을 빕니다.