Question

D'accord, cela me dérange depuis plusieurs années maintenant. Si vous vous êtes habitué aux statistiques et aux mathématiques à l’école, refusez maintenant . Trop tard.

d'accord. Prenez une profonde respiration. Voici les règles. Prenez deux trente dés face (oui, ils existent. ) et les faire rouler simultanément.

  • Ajoutez les deux nombres
  • Si les deux dés indiquent < = 5 ou > = 26, relancez et ajoutez le résultat à ce que vous avez
  • Si l'un est < = 5 et l'autre > = 26, relancez et soustrayez le résultat de ce que vous avez
  • Répétez jusqu'à ce que l'un ou l'autre soit > 5 et & Lt; 26!

Si vous écrivez du code (voir ci-dessous), lancez ces dés plusieurs millions de fois et vous comptez combien de fois vous recevez chaque nombre comme résultat final, vous obtenez une courbe assez plate à gauche de 1, environ 45 # 176; Le degré de probabilité de rouler à 30,5 ou plus est supérieur à 50%, de rouler mieux que 18 à 80% et de rouler mieux que 0 à 97%.

Maintenant, la question: est-il possible d'écrire un programme pour calculer la valeur exacte f (x), c'est-à-dire la probabilité d'obtenir une certaine valeur?

Contexte: pour notre jeu de rôle & "Jungle of Stars &"; nous avons cherché un moyen de contrôler les événements aléatoires. Les règles ci-dessus garantissent un résultat beaucoup plus stable pour quelque chose que vous essayez:)

Pour les geeks des environs, le code 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
Était-ce utile?

La solution

Je devais d'abord réécrire votre code avant de pouvoir le comprendre:

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

Peut-être trouvez-vous cela moins lisible; Je ne sais pas. (Vérifiez si cela correspond à ce que vous aviez à l'esprit.) De plus, en ce qui concerne la façon dont vous utilisez & "Result &"; dans votre code - connaissez-vous la dict s de Python

Quoi qu’il en soit, le style de programmation mis à part: supposons que F (x) soit le CDF sur OW60 (1), c'est-à-dire

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

Laissez de même

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

Ensuite, vous pouvez calculer F (x) à partir de la définition, en additionnant toutes les (30 & # 215; 30) valeurs possibles du résultat du premier lancer. Par exemple, si le premier lancer est (2,3), vous lancerez de nouveau. Ce terme contribue donc (1/30) (1/30) (5 + F (x-5)) à l'expression de F ( X). Donc, vous obtiendrez une longue expression obscène, comme

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

qui est une somme de plus de 900 termes, un pour chaque paire (a, b) dans [30] & # 215; [30]. Les paires (a, b) avec les deux & # 8804; 5 ou les deux & # 8805; 26 ont un terme a + b + F (xab), les paires avec un & # 8804; 5 et un & # 8805; 26 ont un terme a + b + G (xab), et les autres ont un terme comme (a + b), parce que vous ne lancez plus.

De même, vous avez

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

Bien sûr, vous pouvez collecter des coefficients; les seuls termes F rencontrés sont de F (x-60) à F (x-52) et de F (x-10) à F (x-2) (pour a, b & # 8805; 26 ou les deux & # 8804; 5), et les seuls termes G utilisés sont ceux de G (x-35) à G (x-27) (pour l'un de a, b & # 8805; 26 et l'autre # 8804; 5), il y a donc moins de termes que 30 termes. Dans tous les cas, définir le vecteur V (x) comme

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

(par exemple), vous avez (à partir de ces expressions pour F et G) une relation de la forme

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

pour une matrice appropriée A et un vecteur approprié B (que vous pouvez calculer), à partir des valeurs initiales de la forme V (x) = [0 0] pour x suffisamment petit, vous pouvez trouver F (x) et G (x) pour x dans la plage que vous voulez fermer arbitrairement la précision. (Et votre f (x), la probabilité de lancer x, est juste F (x) -F (x-1), donc ça sort aussi.)

Il pourrait y avoir un meilleur moyen. Tout est dit et fait, cependant, pourquoi faites-vous cela? Quel que soit le type de distribution que vous voulez, il existe de belles et simples distributions de probabilités, dotées des paramètres appropriés, dotées de bonnes propriétés (par exemple, une petite variance, des erreurs unilatérales, etc.). Il n'y a aucune raison de créer votre propre procédure ad-hoc pour générer des nombres aléatoires.

Autres conseils

J'ai établi des statistiques de base sur un échantillon de 20 millions de lancers. Voici les résultats:

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)

Les erreurs ont été déterminées expérimentalement. La moyenne arithmétique et le mode sont vraiment précis, et modifier les paramètres de manière même agressive ne semble pas les influencer beaucoup. Je suppose que le comportement de la médiane a déjà été expliqué.

Remarque: ne prenez pas ces chiffres pour une description mathématique correcte de la fonction. Utilisez-les pour obtenir rapidement une image de la distribution. Pour le reste, ils ne sont pas assez précis (même s'ils peuvent être précis.

Cela est peut-être utile pour quelqu'un.

Modifier 2:

" alt "">

Basé sur seulement 991 valeurs. J'aurais pu y mettre plus de valeurs, mais ils auraient déformé le résultat. Cet exemple se trouve être assez typique.

Modifier 1:

voici les valeurs ci-dessus pour un seul dé à soixante faces, à titre de comparaison:

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

Notez que ces valeurs sont calculées et non expérimentales.

La probabilité non composée composée est ... non triviale. J'allais aborder le problème de la même manière que James Curran, mais j'ai vu dans votre code source qu'il pourrait y avoir un troisième jeu de rouleaux, un quatrième, etc. Le problème est résolu mais bien au-delà de la plupart des simulateurs.

Y a-t-il une raison particulière pour laquelle vous avez besoin d'une plage aléatoire de -Inf à + Inf avec une courbe aussi complexe autour de 1 à 60? Pourquoi la courbe en cloche de 2D30 n'est-elle pas acceptable? Si vous expliquez vos besoins, il est probable que quelqu'un fournisse un algorithme plus simple et plus borné.

Eh bien, voyons. Le second lancer (qui sera parfois ajouté ou soustrait au premier rouleau) a une belle courbe en cloche facilement prévisible autour de 31. Le premier rouleau, bien sûr, est le problème.

Pour le premier rouleau, nous avons 900 combinaisons possibles.

  • 50 combinaisons entraînent l'ajout du deuxième rouleau.
  • 25 combinaisons entraînent la soustraction du deuxième rouleau.
  • Laissant 825 combinaisons correspondant à la courbe en cloche du deuxième rouleau.

L'ensemble soustractif (pré-soustraction) formera une courbe en cloche dans la plage (27..35). La moitié inférieure du jeu d’addition formera une courbe en cloche dans la plage (2..10), tandis que la moitié supérieure formera une courbe en cloche dans la plage (52 ... 60)

Ma probabilité est un peu rouillée, donc je ne peux pas calculer les valeurs exactes pour vous, mais il devrait être clair que celles-ci conduisent à des valeurs prévisibles.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top