English 中文(简体)
计算两个 D30 复合投掷的精确结果。
原标题:
  • 时间:2008-11-19 15:57:35
  •  标签:

好的,这已经困扰了我好几年了。如果你在学校里对统计学和高等数学感到很困惑,请立刻离开。为时已晚。

好的。深呼吸。这里是规则。拿两个三十面骰子(是的,它们确实存在),并同时掷出。

  • Add the two numbers
  • If both dice show <= 5 or >= 26, throw again and add the result to what you have
  • If one is <= 5 and the other >= 26, throw again and subtract the result from what you have
  • Repeat until either is > 5 and < 26!

如果你编写一些代码(见下文),将那些骰子滚动几百万次,计算每个数字作为最终结果出现的频率,你会得到一条相当平坦的曲线,左边1的地方几乎平坦,1到60度之间有大约45°角,60以上也是平坦的。掷出30.5或更好的几率大于50%,掷出18以上的几率为80%,掷出0以上的几率为97%。

现在的问题是:是否可能编写一个计算确切值f(x)即掷出特定值的概率的程序?

背景:为了我们的角色扮演游戏《星际丛林》,我们寻找一种方法来控制随机事件。上述规则保证您尝试的事情会有更稳定的结果 :)

对于周围的极客,Python 中的代码:

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
  % 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

也许您可能会觉得这篇文章不易读;我不知道。(请检查是否等同于您想表达的内容。)另外,关于您在代码中使用“result”的方式——您是否了解Python的字典

无论编程风格如何:假设F(x)是OW60(1)的累积分布函数CDF。

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

同样地,让

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

然后,您可以从定义中计算F(x),通过对第一次掷骰子的所有(30×30)可能值求和。例如,如果第一次掷骰子是(2,3),则您将再次掷骰子,因此此项对F(x)的表达式有贡献(1/30)(1/30)(5+F(x-5)) 。所以你会得到一些极其复杂的表达式,如:

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

这是900个项目的总和,每对(a,b)在[30]×[30]中有一个。对于两个≤5或两个≥26的对(a,b),有一个项a+b+F(x-a-b),其中一≤5且另一个≥26的对具有一个项a+b+G(x-a-b),其余的项如(a+b),因为您不会再次掷骰子。

同樣地,你有。 (Tóngyàng de, nǐ yǒu.)

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(您可以计算),因此从形式为V(x)= [0 0]的初始值开始,对于足够小的x,您可以找到x所需的任意精度的F(x)和G(x)。 (而您的f(x),即抛掷x的概率,只是F(x)-F(x-1),因此也出现了。)

可能有更好的方法。不过,你为什么要这样做呢?无论你想要哪种类型的分布,都有一些漂亮而简单的概率分布,具有良好的属性(例如,小方差,单边误差,等等),并且具有适当的参数。没有理由编制自己的临时过程来生成随机数。

问题回答

我对2000万次投掷进行了一些基本的统计分析。以下是结果:

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个值。我可以把更多的值塞进去,但它们会扭曲结果。这个样本恰好比较典型。

编辑1:

以下是仅一个六十面骰子的上述数值,供对比:

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

请注意,这些值是计算出来的,而不是实验得出的。

复合无界概率是非平凡的。我本来打算像詹姆斯·卡伦那样解决问题,但是从你的源代码中我看到可能会有第三组、第四组等等。这个问题是可以解决的,但是超出了大多数掷骰子模拟器的能力范围。

你为什么需要一个从负无穷到正无穷的带有如此复杂曲线的随机范围?为什么2D30的钟形曲线不可接受?如果你解释一下你的需求,可能会有人能提供一个更简单和更有限的算法。

嗯,让我们看看。第二个投掷(有时将被添加或减去到第一次掷骰子)有一个漂亮并容易预测的钟形曲线,大约为31。当然,第一次掷骰子是个问题。

第一次投掷,我们有900种可能的组合。

  • 50 combinations result in adding the second roll.
  • 25 combinations result in subtracting the second roll.
  • Leaving 825 combinations which match the bell curve of the second roll.

The subtracting set (pre-subtraction) will form a bell curve in the range (27..35). The lower half of the adding set will form a bell curve in the range (2..10), while the upper half will form a bell curve in the range (52...60)

我的概率有点生疏,所以我不能为您计算出确切的值,但应该清楚这些会导致可预测的值。





相关问题
热门标签