3

さて、これは数年間私を悩ませました。学校で統計学や高等数学に夢中になっている場合は、今すぐやめてください。遅すぎる。

わかった。深呼吸する。ルールは次のとおりです。2 つの30 面ダイス (はい、存在します) を取り、同時に転がします。

  • 2 つの数字を足す
  • 両方のサイコロが 5 以下または 26 以上の場合は、もう一度投げてその結果を自分の持っているものに追加します。
  • 1 つが <= 5 で、もう 1 つが >= 26 の場合は、もう一度投げて、その結果を自分の持っているものから引きます。
  • どちらかが > 5 かつ < 26 になるまで繰り返します!

いくつかのコードを記述し (以下を参照)、それらのサイコロを数百万回転がし、最終結果として各数字を受け取る頻度を数えると、1 の左側でかなり平坦な曲線が得られます。1 と 1 の間は約 45° です。 60 以上でフラット。30.5 以上になる確率は 50% 以上、18 以上になる確率は 80%、0 以上になる確率は 97% です。

ここで質問です:正確な値 f(x)、つまり特定の値をロールする確率を計算するプログラムを書くことは可能ですか?

背景: ロールプレイング ゲーム「Jungle of Stars」では、ランダムなイベントを抑える方法を探しました。上記のルールは、あなたが試みる何かに対してより安定した結果を保証します:)

オタク向けの 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) の場合、もう一度ロールするので、この項は (1/30)(1/30)(5+F(x-5)) を F( の式に寄与します。バツ)。したがって、次のようなわいせつな長い式が得られます

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

これは、[30]×[30] の各ペア (a,b) に 1 つずつ、900 項の合計です。両方が 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 の 1 つと他の ≤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 に対して。(そして、x を投げる確率である f(x) は、ちょうど F(x)-F(x-1) であるため、それも出てきます。)

もっと良い方法があるかもしれません。とはいえ、なぜあなたはこれをしているのですか?どのような種類の分布を希望する場合でも、適切なパラメーターを使用して、優れた特性 (分散が小さい、片側誤差など) を持つ単純な確率分布があります。乱数を生成するために独自の特別な手順を作成する理由はありません。

于 2008-11-20T15:29:30.303 に答える
2

2,000 万回のスローのサンプルについて、いくつかの基本的な統計を作成しました。結果は次のとおりです。

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 面ダイス 1 つだけの上記の値を次に示します。

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 と同じ方法で問題に取り組むつもりでしたが、ソース コードから、3 番目のロール セット、4 番目のロール セットなどがある可能性があることがわかりました。この問題は解決可能ですが、ほとんどのサイコロ転がしシミュレータをはるかに超えています。

-Inf から +Inf までのランダムな範囲が必要で、1 ~ 60 付近の複雑な曲線が必要な特定の理由はありますか? 2D30 のベル曲線が受け入れられないのはなぜですか? 要件を説明すれば、誰かがより単純で境界のあるアルゴリズムを提供できる可能性があります。

于 2008-11-19T21:35:51.500 に答える
0

さて、見てみましょう。2 番目のスロー(最初のロールに加算または減算されることもあります) は、31 付近で簡単に予測できる良好なベル カーブを持っています。もちろん、最初のロールが問題です。

最初のロールでは、900 の可能な組み合わせがあります。

  • 50 の組み合わせで 2 番目のロールが追加されます。
  • 25 の組み合わせでは、2 番目のロールが差し引かれます。
  • 2 番目のロールのベル カーブに一致する 825 の組み合わせを残します。

減算セット (減算前) は、範囲 (27..35) でベル カーブを形成します。追加セットの下半分は範囲 (2..10) でベル カーブを形成し、上半分は範囲 (52...60) でベル カーブを形成します。

私の確率は少しさびているので、正確な値を把握することはできませんが、これらが予測可能な値につながることは明らかです.

于 2008-11-19T16:20:37.423 に答える