Domanda

Ok, questo mi ha ostacolato per diversi anni, ora.Se hai preso in statistica e superiori di matematica a scuola, di voltare le spalle, ora.Troppo tardi.

Va bene.Prendere un respiro profondo.Queste sono le regole.Prendere due trenta facce (sì, esistono) e li rotolo contemporaneamente.

  • Aggiungere i due numeri
  • Se entrambi i dadi mostrano <= 5 o >= 26, lanciare di nuovo e aggiungere il risultato di quello che hai
  • Se uno è <= 5 e gli altri >= 26, lanciare di nuovo e sottrarre il risultato da quello che hai
  • Ripetere fino a quando è > 5 e < 26!

Se si scrive un po ' di codice (vedi sotto), tira i dadi un paio di milioni di volte e ti rendi conto quanto spesso si riceve ogni numero come risultato, si ottiene una curva che è praticamente piatto a sinistra di 1, di circa 45° gradi tra 1 e 60 e tv a al di sopra del 60.La possibilità di rotolare 30.5 o meglio è maggiore del 50%, a rotolare meglio di 18 è 80% e un rotolo di meglio che 0 è del 97%.

Ora la domanda:È possibile scrivere un programma per calcolare il esatto il valore di f(x), cioèla probabilità di tirare un certo valore?

Sfondo:Per il nostro gioco di ruolo "Giungla di Stelle", abbiamo cercato un modo per tenere eventi casuali di controllo.Le regole di cui sopra garantire una maggiore stabilità al risultato per qualcosa che si prova :)

Per i geek di tutto il codice in 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
È stato utile?

Soluzione

Ho dovuto prima di riscrivere il codice prima che io possa capire:

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

Forse si potrebbe trovare questo meno leggibile;Non so.(Controllare se è equivalente a quello che si aveva in mente.) Inoltre, per quanto riguarda il modo in cui si utilizza il "risultato" nel codice -- siete a conoscenza di Python dicts?

Comunque, questioni di stile di programmazione da parte:Supponiamo che F(x) è la CDF di OW60(1), cioè

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

Allo stesso modo lasciare

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

Quindi è possibile calcolare F(x) dalla definizione, sommando su tutti (30×30) i possibili valori del risultato del primo lancio.Per esempio, se il primo tiro è (2,3) poi ti tira ancora, quindi questo termine contribuisce (1/30)(1/30)(5+F(x-5)) per l'espressione di F(x).Così si otterrà alcuni oscenamente lungo espressione come

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

che è una somma di oltre 900 termini, uno per ogni coppia (a,b) [30]×[30].Le coppie (a,b) con entrambi i ≤ 5 o entrambi ≥26 di avere un periodo a+b+F(x-a-b), le coppie con uno ≤5 ≥26 di avere un periodo a+b+G(x-a-b), e il resto hanno un termine come (a+b), perché non lanciare di nuovo.

Analogamente, ci sono

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

Naturalmente, è possibile raccogliere i coefficienti;il solo F condizioni che si verificano sono da F(x-60) e F(x-52) e da F(x-10) e F(x-2) (a,b≥26 o entrambi≤5), e il solo G condizioni che si verificano sono da G(x-35) a G(x-27) (per uno di a,b≥26 e l'altro ≤5), quindi ci sono meno termini di 30 termini.In ogni caso, la definizione di vettore V(x) come

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

(dire), si ha (a partire da quelli delle espressioni di F e G) una relazione della forma

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

per un'opportuna matrice A e un opportuno vettore B (che si può calcolare), quindi, a partire da valori iniziali della forma V(x) = [0 0] per x sufficientemente piccolo, è possibile trovare F(x) e G(x) per x nell'intervallo che si desidera arbitrariamente vicino precisione.(E, f(x), la probabilità di lancio di x, è proprio F(x)-F(x-1), in modo che viene fuori pure.)

Ci potrebbe essere un modo migliore.Tutto detto e fatto, però, perché stai facendo questo?Qualunque sia il tipo di distribuzione che si desidera, ci sono belle e semplici distribuzioni di probabilità, con i parametri appropriati, che hanno buone proprietà (ad es.piccola varianza, unilaterale errori, a prescindere).Non c'è motivo di fare il vostro proprio ad hoc procedura per generare numeri casuali.

Altri suggerimenti

Ho fatto alcune statistiche di base su un campione di 20 milioni di tiri.Ecco i risultati:

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)

Gli errori sono stati determinati sperimentalmente.La media aritmetica e la modalità sono davvero accurata, e di modificare i parametri anche abbastanza aggressivo non sembra incidere più di tanto.Suppongo che il comportamento della mediana è già stato spiegato.

Nota:non prendere questi numeri per una corretta descrizione matematica della funzione.Li usa per ottenere rapidamente un quadro di ciò che la distribuzione sembra.Per tutto il resto, non sono abbastanza precise (anche se potrebbero essere precisi.

Forse questo è utile a qualcuno.

Edit 2:

graph

Basato sul solo 991 valori.Ho potuto stipati di più i valori in esso, ma si sarebbe falsato il risultato.Questo esempio sembra essere abbastanza tipico.

Edit 1:

qui ci sono i valori di cui sopra per un solo sessanta parteggiato muore, per il confronto:

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

Si noti che questi valori sono stati calcolati, non sperimentale.

Composto sovrabbondanza di probabilità è...non banale.Stavo per affrontare il problema stesso modo come James Curran, ma poi ho visto dal tuo codice sorgente che ci potrebbe essere una terza serie di rulli, e un quarto, e così via.Il problema è risolvibile, ma ben oltre la maggior parte die rolling simulatori.

C'è qualche motivo particolare che avete bisogno di un casuale gamma da -Inf a +Inf con una curva complessa intorno 1-60?Perché la curva a campana di 2D30 non accettabile?Se spiegate le vostre esigenze, è probabile che qualcuno potesse fornire un modo più semplice e delimitata algoritmo.

Beh, staremo a vedere.Il secondo passi (che a volte può essere aggiunto o sottratto al primo tiro) ha un bel facilmente prevedibile curva a campana, circa 31.Il primo tiro, naturalmente, è il problema.

Per il primo lancio, abbiamo 900 combinazioni possibili.

  • 50 combinazioni di risultato in aggiunta il secondo rotolo.
  • 25 combinazioni di risultato in sottraendo il secondo rotolo.
  • Lasciando 825 combinazioni che partita la curva a campana del secondo tiro.

La sottrazione di imposta (pre-sottrazione) si forma una curva a campana nell'intervallo (27..35).La metà inferiore della finestra di aggiunta di set di formare una curva a campana nell'intervallo (2..10), mentre la metà superiore si forma una curva a campana nell'intervallo (52...60)

Il mio probablity è un po ' arrugginito, quindi non posso calcolare i valori esatti, ma dovrebbe essere chiaro che questi conducono a valori stimabili.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top