2008-11-19 2 views
3

Хорошо, это прослушивало меня уже несколько лет. Если вы сосали статистику и высшую математику в школе, отвратитесь, сейчас. Слишком поздно.Вычислите точный результат сложного броска двух D30

Хорошо. Сделайте глубокий вдох. Вот правила. Возьмите два тридцатисторонних кубика (да, they do exist) и сверните их одновременно.

  • Добавить два номера
  • Если оба кубика показывают < = 5 или> = 26, бросить снова и добавить результатом того, что у вас есть
  • Если один < = 5, а другая> = 26, бросить снова и вычесть результат из у вас есть
  • Повторяйте до тех пор, пока не будет> 5 и < 26!

Если вы напишете какой-нибудь код (см. Ниже), сверните эти кости несколько миллионов раз, и вы рассчитываете, как часто вы получаете каждое число в качестве конечного результата, вы получаете кривую, которая довольно плоская слева от 1, вокруг 45 ° градусов между 1 и 60 и плоскими выше 60. Вероятность прокатки 30,5 или выше составляет более 50%, для прокатки лучше 18 составляет 80%, а для прокатки лучше, чем 0, составляет 97%.

Теперь вопрос: можно ли написать программу стоимоститочного значения f (х), то есть вероятность того, катиться определенным значением?

Справочная информация. Для нашей ролевой игры «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 
+0

Кривая, которую вы описываете, является кумулятивной вероятностью. Интересна кривая плотности вероятности для этих данных. Он имеет два ясных вершины (один на 26 и один на 36), с долиной в средней точке (31). Только это заставляет меня думать, что ваш ответ будет трудно определить! – 2008-11-19 22:41:08

+0

Я знаю :) Я уже обращался к профессорам за статистикой, и они не могли придумать ответа ... – 2008-11-20 07:54:32

+0

, который должен был быть «двумя профессорами» – 2008-11-20 07:58:13

ответ

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 

Может быть, вы могли бы найти это менее читаемыми; Я не знаю. (Проверьте, соответствует ли это тому, что вы имели в виду.) Также, в отношении того, как вы используете «результат» в своем коде - знаете ли вы о dict s Python?

Во всяком случае, вопросы стиля программирования в сторону: Пусть F (х) является CDF из OW60 (1), т.е.

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

Точно так же пусть

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

Тогда можно вычислить F (х) из определения, суммируя по всем (30 × 30) возможные значения результата первого броска. Например, если первый бросок (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)) 

который представляет собой сумму более 900 терминов, по одному для каждой пары (а, б) в [30] × [30]. Пар (a, b) с ≤5 или оба ≥26 имеют член a + b + F (xab), пары с одним ≤5 и одним ≥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 (х), как

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), так что это тоже получается.)

Возможно, будет лучший способ. Однако все сказанное и сделанное, почему вы это делаете? Независимо от того, какой тип распределения вы хотите, есть хорошие и простые распределения вероятностей с соответствующими параметрами, которые имеют хорошие свойства (например, небольшая дисперсия, односторонние ошибки, что угодно). Нет причин составлять вашу собственную ad-hoc-процедуру для генерации случайных чисел.

0

Ну, давайте посмотрим. Второй бросок (который иногда добавляется или вычитается в первый рулон) имеет хорошую легко прогнозируемую кривую колокола около 31. Первый бросок, конечно же, является проблемой.

Для первого рулона у нас есть 900 возможных комбинаций.

  • 50 комбинаций приводят к добавлению второго рулона.
  • 25 комбинаций приводят к вычитанию второго рулона.
  • Оставляя 825 комбинаций, соответствующих кривой звонка второго рулона.

Вычитающий набор (предварительное вычитание) образует кривую колокола в диапазоне (27..35). Нижняя половина добавочного набора образует кривую колокола в диапазоне (2..10), а верхняя половина образует кривую колокола в диапазоне (52 ... 60).

Моя вероятность - это бит ржавый, поэтому я не могу определить точные значения для вас, но должно быть ясно, что они приводят к предсказуемым значениям.

+0

Кажется, вы прочитали проблему так же, как я, что неверно , Его исходный код иллюстрирует, что может быть третий рулон, или четвертый, или пятый ... – Sparr 2008-11-19 21:12:41

1

Составная неограниченная вероятность ... нетривиальная.Я собирался решить проблему так же, как Джеймс Карран, но потом я увидел из вашего исходного кода, что может быть третий набор рулонов, четвертый и т. Д. Проблема разрешима, но далеко за пределами большинства симуляторов качения.

Есть ли какая-то конкретная причина, по которой вам нужен случайный диапазон от -Inf до + Inf с такой сложной кривой около 1-60? Почему кривая звонка 2D30 неприемлема? Если вы объясните свои требования, вероятно, кто-то может предоставить более простой и более ограниченный алгоритм.

2

Я сделал базовую статистику по выборке из 20 миллионов бросков.Ниже приведены результаты:

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) 

Ошибки были определены экспериментально. Среднее арифметическое и режим действительно точны, и изменение параметров даже довольно агрессивно не влияет на них. Я полагаю, что поведение медианы уже объяснено.

Примечание: не используйте эти цифры для правильного математического описания функции. Используйте их, чтобы быстро получить представление о том, как выглядит распределение. Для чего-то еще, что они не достаточно точны (несмотря на то, что они могли бы быть точным

Может быть, это полезно для кого

Edit 2:..

graph

основе всего 991 значений Я мог бы перегрузить больше значений, но они бы исказили результат. Этот пример довольно типичен.

Редактировать 1:

здесь вышеуказанные значения только для одной шестьдесят односторонней фильеры, для сравнения:

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

Обратите внимание, что эти значения вычисляются, а не экспериментальные.

Смежные вопросы