Pregunta

Bien, esto me molestó durante varios años, ahora. Si absorbió estadísticas y matemáticas superiores en la escuela, apártese, ahora . Demasiado tarde.

De acuerdo. Tomar una respiración profunda. Estas son las reglas. Tome dos treinta dados dados (sí, sí existen ) y gírelos simultáneamente.

  • Agregue los dos números
  • Si ambos dados muestran < = 5 o > = 26, tira de nuevo y agrega el resultado a lo que tienes
  • Si uno es < = 5 y el otro > = 26, arroje nuevamente y reste el resultado de lo que tienes
  • Repita hasta que sea > 5 y & Lt; 26!

Si escribe algún código (vea más abajo), tire esos dados unos millones de veces y cuente con qué frecuencia recibe cada número como resultado final, obtendrá una curva que es bastante plana a la izquierda de 1, ¡alrededor de 45 # 176; grados entre 1 y 60 y plano por encima de 60. La posibilidad de sacar 30.5 o más es mayor al 50%, rodar mejor que 18 es 80% y rodar mejor que 0 es 97%.

Ahora la pregunta: ¿es posible escribir un programa para calcular el valor exacto f (x), es decir, la probabilidad de obtener cierto valor?

Antecedentes: para nuestro juego de rol " Jungle of Stars " buscamos una forma de mantener controlados los eventos aleatorios. Las reglas anteriores garantizan un resultado mucho más estable para algo que intentas :)

Para los geeks, el código en 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
¿Fue útil?

Solución

Primero tuve que reescribir su código antes de poder entenderlo:

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

Quizás pueda encontrar esto menos legible; No lo sé. (Verifique si es equivalente a lo que tenía en mente.) Además, con respecto a la forma en que usa & Quot; result & Quot; en su código: ¿conoce el dict s?

de Python

De todos modos, aparte del estilo de programación: supongamos que F (x) es CDF de OW60 (1), es decir

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

De forma similar, deja

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

Entonces puedes calcular F (x) a partir de la definición, sumando todos los valores posibles (30 & # 215; 30) del resultado del primer lanzamiento. Por ejemplo, si el primer lanzamiento es (2,3), entonces rodará nuevamente, por lo que este término contribuye (1/30) (1/30) (5 + F (x-5)) a la expresión para F ( X). Entonces obtendrás una expresión obscenamente larga como

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

que es una suma de más de 900 términos, uno para cada par (a, b) en [30] & # 215; [30]. Los pares (a, b) con ambos & # 8804; 5 o ambos & # 8805; 26 tienen un término a + b + F (xab), los pares con uno & # 8804; 5 y uno & # 8805; 26 tienen un término a + b + G (xab), y el resto tiene un término como (a + b), porque no vuelves a tirar.

Similarmente tienes

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

Por supuesto, puede recopilar coeficientes; los únicos términos F que ocurren son de F (x-60) a F (x-52) y de F (x-10) a F (x-2) (para a, b & # 8805; 26 o ambos & # 8804; 5), y los únicos términos G que ocurren son de G (x-35) a G (x-27) (para uno de a, b & # 8805; 26 y el otro # 8804; 5), por lo que hay menos términos que 30 términos. En cualquier caso, definiendo el vector V (x) como

V(x) = [F(x-60) G(x-60) ... F(x-2) G(x-2) F(x-1) G(x-1) F(x) G(x)]

(digamos), tiene (de esas expresiones para F y G) una relación de la forma

V(x) = A*V(x-1) + B

para una matriz A apropiada y un vector B apropiado (que puede calcular), por lo que a partir de los valores iniciales de la forma V (x) = [0 0] para x lo suficientemente pequeño, puede encontrar F (x) y G (x) para x en el rango que desea cerrar arbitrariamente la precisión. (Y su f (x), la probabilidad de arrojar x, es solo F (x) -F (x-1), por lo que también sale.)

Puede haber una mejor manera. Todo dicho y hecho, sin embargo, ¿por qué haces esto? Independientemente del tipo de distribución que desee, hay distribuciones de probabilidad simples y agradables, con los parámetros apropiados, que tienen buenas propiedades (por ejemplo, pequeña varianza, errores unilaterales, lo que sea). No hay ninguna razón para crear su propio procedimiento ad-hoc para generar números aleatorios.

Otros consejos

He hecho algunas estadísticas básicas en una muestra de 20 millones de lanzamientos. Aquí están los resultados:

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)

Los errores se determinaron experimentalmente. La media aritmética y el modo son realmente precisos, y cambiar los parámetros incluso de forma bastante agresiva no parece influir mucho en ellos. Supongo que el comportamiento de la mediana ya se ha explicado.

Nota: no tome estos números para una descripción matemática adecuada de la función. Úselos para obtener rápidamente una imagen de cómo se ve la distribución. Para cualquier otra cosa, no son lo suficientemente precisos (a pesar de que podrían ser precisos.

Quizás esto sea útil para alguien.

Editar 2:

 graph

Basado en solo 991 valores. Podría haber metido más valores en él, pero habrían distorsionado el resultado. Esta muestra resulta ser bastante típica.

Editar 1:

aquí están los valores anteriores para solo un dado de sesenta lados, para comparar:

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

Tenga en cuenta que estos valores se calculan, no son experimentales.

La probabilidad ilimitada compuesta es ... no trivial. Iba a abordar el problema de la misma manera que James Curran, pero luego vi en su código fuente que podría haber un tercer conjunto de rollos, y un cuarto, y así sucesivamente. El problema es solucionable, pero mucho más allá de la mayoría de los simuladores de lanzamiento de dados.

¿Hay alguna razón particular por la que necesite un rango aleatorio de -Inf a + Inf con una curva tan compleja alrededor de 1-60? ¿Por qué la curva de campana de 2D30 no es aceptable? Si explica sus requisitos, es probable que alguien pueda proporcionar un algoritmo más simple y acotado.

Bueno, veamos. El segundo lanzamiento (que a veces se agregará o restará al primer lanzamiento) tiene una curva de campana agradable y fácilmente predecible alrededor de 31. El primer lanzamiento, por supuesto, es el problema.

Para el primer lanzamiento, tenemos 900 combinaciones posibles.

  • 50 combinaciones resultan en agregar el segundo rollo.
  • 25 combinaciones resultan en restar el segundo lanzamiento.
  • Dejando 825 combinaciones que coinciden con la curva de campana del segundo lanzamiento.

El conjunto de resta (pre-resta) formará una curva de campana en el rango (27..35). La mitad inferior del conjunto sumador formará una curva de campana en el rango (2..10), mientras que la mitad superior formará una curva de campana en el rango (52 ... 60)

Mi probabilidad es un poco oxidada, por lo que no puedo calcular los valores exactos para usted, pero debe quedar claro que estos conducen a valores predecibles.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top