2010-04-21 179 views
4

我正在嘗試計算不斷變化的6面擲骰數量的賠率分佈。例如,3D6從3範圍爲18如下:使用6面骰子計算賠率分佈

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 

我寫這個PHP程序來計算的話:

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; 
} 

for循環內附加$ J採用地板的魔力和模量函數來創建與數字在骰子的數目的數目的基-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個骰子,會擲出多少個3) – rlbond 2010-04-22 20:06:14

1

好了,讓我們開始滾動只是一個模具。我們知道平均值是3.5。我們還可以計算方差,其中M是平均值,x是骰子結果,並且p是該骰子結果的概率。使用這個公式,單個骰子滾動的方差爲35/12 = 1/6 *(( - 2.5)^ 2 +(-1.5)^ 2 +( - 0.5)^ 2 + 0.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的正態分佈,假設你擲出了相當數量的骰子,這將是一個非常好的選擇。

3

在PERL:

#! 
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

對代碼的某些解釋會對那些閱讀您的答案有幫助 – 2012-12-13 21:55:47

0

我不知道是否有跳過啃數量和直行到曲線本身的一種方式。有沒有辦法做到這一點,例如,80D6(範圍:80-480)?該分佈可以在不進行6^80計算的情況下進行預測嗎?

是。自變量之和的概率函數是每個變量的概率函數的卷積。

在這種情況下的卷積只是一個特殊的總和。 (更一般地說,卷積是一個積分。)設p和q是兩個離散的概率函數。卷積通常用星號表示。

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

其中i的範圍從1到(N_P + n_q - 1)N_P爲p的元素的數量和n_q Q的元素的數量。如果(i - j + 1)小於1或大於n_q,則令q [i - j + 1]爲零(所以這些項從求和中消失)。

在這種情況下,您有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個p)... * 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,你會發現數字變得越來越像一個正態分佈。這是中心極限定理的例證。

完全有可能我在編制索引時犯了一些錯誤,因此您需要檢查它。希望這可以解決這個問題。