【问题标题】:Calculating odds distribution with 6-sided dice用 6 面骰子计算赔率分布
【发布时间】:2011-02-10 16:50:18
【问题描述】:

我正在尝试计算不断变化的 6 面掷骰数的几率分布。例如,3d6 的范围从 3 到 18 如下:

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

内部 $j for 循环使用 floormodulus 函数的魔力来创建一个以 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 个可能的结果,并将 1 添加到 $distribution 数组中 3 到 18 之间的相应槽。非常简单。但是,它只工作到大约 8d6,之后我得到服务器超时,因为它现在正在进行数十亿次计算。

但我认为没有必要,因为死亡概率遵循甜美的钟形曲线分布。我想知道是否有办法跳过数字运算并直接进入曲线本身。有没有办法做到这一点,例如,80d6(范围:80-480)?不进行 6^80 次计算,可以预测分布吗?

我不是专业的编码员,概率对我来说还是个新手,所以感谢所有帮助!

斯蒂芬

【问题讨论】:

    标签: distribution probability dice


    【解决方案1】:

    我想知道是否有一种方法可以跳过数字运算并直接进入曲线本身。有没有办法做到这一点,例如,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 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,你会发现数字变得越来越像一个正态分布。这是中心极限定理的说明。

    我完全有可能在索引方面犯了一些错误,因此您需要检查一下。希望这能对问题有所启发。

    【讨论】:

      【解决方案2】:

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

      【讨论】:

      • 对代码的一些解释将对阅读您的答案的人有所帮助
      【解决方案3】:

      好的,让我们从掷一个骰子开始吧。我们知道平均值是 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 的正态分布,假设您掷的骰子数量可观,这将是一个非常合适的分布。

      【讨论】:

        【解决方案4】:

        您正在寻找Binomial Distribution

        【讨论】:

        • 二项分布无法模拟掷骰的 sum,只能模拟单个结果(例如,如果我们掷 40 个骰子,将掷出多少个 3)
        猜你喜欢
        • 2011-01-19
        • 2020-09-02
        • 1970-01-01
        • 2021-09-23
        • 2020-03-22
        • 1970-01-01
        • 2014-08-07
        • 2011-09-30
        • 2012-05-11
        相关资源
        最近更新 更多