用6面骰子计算赔率分布

时间:2010-04-21 16:29:51

标签: distribution probability dice

我正在尝试计算不断变化的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-loop使用 floor 模数函数的魔力来创建base-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之间的$ distribution数组中的相应插槽中加1。非常简单。然而,它只能工作到大约8d6,之后我得到服务器超时,因为它现在正在做数十亿的计算。

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

我不是一个专业的程序员,对我来说概率仍然是新的,所以感谢所有的帮助!

斯蒂芬

4 个答案:

答案 0 :(得分: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;
}

答案 1 :(得分:1)

您正在寻找Binomial Distribution

答案 2 :(得分: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的正态分布,假设你滚动了相当数量的骰子,这将是一个非常合适的选择。

答案 3 :(得分: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,您会发现数字越来越像正态分布。这是中心极限定理的例证。

完全有可能我在索引方面犯了一些错误,所以你要检查一下。希望这能够解决这个问题。