3

好吧,这困扰了我好几年,现在。如果你在学校学过统计学和高等数学,现在就转身离开。太晚了。

好的。深吸一口气。这是规则。拿两个30 面骰子(是的,它们确实存在)并同时掷骰子。

  • 将两个数字相加
  • 如果两个骰子都显示 <= 5 或 >= 26,再次掷骰子并将结果添加到您所拥有的
  • 如果一个是 <= 5 而另一个 >= 26,则再次抛出并从你拥有的结果中减去结果
  • 重复直到 > 5 和 < 26!

如果您编写一些代码(见下文),将这些骰子掷几百万次,然后计算您收到每个数字的频率作为最终结果,您会得到一条在 1 的左侧非常平坦的曲线,在 1 和 1 之间大约 45° 60和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\n' % 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
4

4 回答 4

6

我必须先重写你的代码才能理解它:

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

也许你会发现这不太可读;我不知道。(请检查它是否与您的想法相同。)另外,关于您在代码中使用“结果”的方式——您知道 Python 的dict吗?

无论如何,抛开编程风格的问题:假设 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.

然后,您可以通过对第一次投掷结果的所有 (30×30) 可能值求和,根据定义计算 F(x)。例如,如果第一次投掷是 (2,3),那么您将再次投掷,因此该项对 F( X)。所以你会得到一些很长的表情,比如

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

这是超过 900 个术语的总和,[30]×[30] 中的每一对 (a,b) 一个。两者均≤5或均≥26的对(a,b)具有项a+b+F(xab),具有1个≤5且1个≥26的对具有项a+b+G(xab),并且其余的有一个像 (a+b) 这样的术语,因为你不会再扔了。

同样你有

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 足够小,您可以找到 F(x) 和 G(x ) 对于 x 在您想要任意接近精度的范围内。(而你的 f(x),即抛出 x 的概率,只是 F(x)-F(x-1),所以也可以得出。)

可能有更好的方法。然而,一切都说了又做了,你为什么要这样做?无论您想要哪种分布,都有很好且简单的概率分布,具有适当的参数,具有良好的属性(例如小方差、单边误差等)。没有理由编写自己的临时程序来生成随机数。

于 2008-11-20T15:29:30.303 回答
2

我已经对 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:

图形

仅基于 991 个值。我本可以在其中塞入更多值,但它们会扭曲结果。这个样本恰好是相当典型的。

编辑1:

以下是仅一个 60 面骰子的上述值,用于比较:

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

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

于 2010-08-08T17:12:44.213 回答
1

复合无界概率是......非平凡的。我打算像 James Curran 一样解决这个问题,但后来我从你的源代码中看到可能有第三组卷,第四组,依此类推。这个问题是可以解决的,但远远超出了大多数滚模模拟器。

是否有任何特殊原因需要从 -Inf 到 +Inf 的随机范围以及 1-60 左右的如此复杂的曲线?为什么2D30的钟形曲线不能接受?如果你解释你的要求,很可能有人可以提供一个更简单、更有界的算法。

于 2008-11-19T21:35:51.500 回答
0

走着瞧。第二投掷(有时会在第一次投掷中添加或减去)在 31 附近有一个很好的易于预测的钟形曲线。当然,第一次投掷是问题所在。

对于第一卷,我们有 900 种可能的组合。

  • 50 种组合导致添加第二卷。
  • 25 个组合导致减去第二个掷骰。
  • 留下 825 个与第二卷的钟形曲线相匹配的组合。

减法集(预减法)将在 (27..35) 范围内形成钟形曲线。加法集的下半部分将在 (2..10) 范围内形成钟形曲线,而上半部分将在 (52...60) 范围内形成钟形曲线

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

于 2008-11-19T16:20:37.423 回答