Pergunta

Ok, isso me incomodava há vários anos, agora. Se você sugado em estatística e matemática avançada na escola, afastam-se, agora . Muito tarde.

Ok. Respire fundo. Aqui estão as regras. Tome dois trinta lados dados (sim, eles existem ) and roll-los simultaneamente.

  • Adicione os dois números
  • Se ambos os dados mostram <= 5 ou> = 26, joga novamente e Adicionar o resultado para o que você tem
  • Se um é <= 5 e outro> = 26, joga novamente e subtrair o resultado do que você tem
  • Repita até que é> 5 e <26! ??

Se você escrever algum código (ver abaixo), jogar esses dados alguns milhões de vezes e você contar quantas vezes você receber cada número como o resultado final, você tem uma curva que é bastante plana deixou de 1, cerca de 45 ° graus entre 1 e 60 e acima plana 60. a possibilidade de rolo de 30,5 ou superior é maior do que 50%, ao rolo melhor do que 18% e é de 80 a rolo melhor do que 0 é de 97%.

Agora, a pergunta:? É possível escrever um programa para calcular exata valor f (x), ou seja, a probabilidade de rolar um certo valor

Antecedentes: Para o nosso Role Playing Game "Jungle of Stars" buscamos uma maneira de manter eventos aleatórios em cheque. As regras acima garantir um resultado muito mais estável para algo que você tente:)

Para os geeks ao redor, o código em 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
Foi útil?

Solução

Eu tive que primeiro reescrever seu código antes que eu pudesse entendê-lo:

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

Talvez você pode encontrar este menos legível; Eu não sei. (Verificação de fazer se ele é equivalente ao que você tinha em mente.) Além disso, em relação à maneira como você usa "resultado" em seu código - você sabe de Python dict s?

De qualquer forma, questões de estilo de programação de lado: Suponha que F (x) é a CDF de OW60 (1), isto é,

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

Da mesma forma vamos

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

Em seguida, você pode calcular F (x) a partir da definição, pela soma sobre todos (30 × 30) possíveis valores do resultado do primeiro lance. Por exemplo, se o primeiro lance é (2,3), então você vai rolar de novo, então este prazo contribui (1/30) (1/30) (5 + F (x-5)) para a expressão para F ( x). Então você vai ter alguns obscenamente longa expressão como

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

que é uma soma sobre 900 termos, um para cada par (a, b) em [30] × [30]. Os pares (a, b), com ambos = 5 ou ambos =26 têm um prazo a + b + F (xab), os pares com um =5 e um =26 têm um prazo a + b + G (xab), e o resto tem um termo como (a + b), porque você não jogue novamente.

Da mesma forma que você tem

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

Claro, você pode coletar coeficientes; as únicas condições F que ocorrem são a partir de F (x-60) a F (x-52) e de F (x-10) a F (x-2) (para uma, ou b=26 both=5), e as únicas condições G que ocorrem são de G (x-35) a G (x-27) (para uma de, uma b=26 e o ??outro =5), de modo que há menos do que 30 termos termos. Em qualquer caso, definindo o vector V (x) como o

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), você tem (a partir dessas expressões para F e G) uma relação de forma

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

para uma matriz apropriada A e uma apropriada vector B (que pode calcular), de modo a começar a partir dos valores iniciais de forma V (x) = [0 0] para x suficientemente pequeno, pode encontrar F (x) e G (x) para x no intervalo que deseja arbitrariamente próximo precisão. (E o seu f (x), a probabilidade de jogar x, é apenas F (x) -F (x-1), de modo que sai bem.)

Pode haver uma maneira melhor. Tudo dito e feito, porém, por que você está fazendo isso? Qualquer tipo de distribuição que você quer, existem distribuições de probabilidade agradável e simples, com os parâmetros apropriados, que têm boas propriedades (por exemplo variação pequena, os erros de um lado, qualquer que seja). Não há nenhuma razão para fazer o seu próprio procedimento ad-hoc para gerar números aleatórios.

Outras dicas

Eu fiz algumas estatísticas básicas sobre uma amostra de 20 milhões de lança. Aqui estão os 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)

Os erros foram determinadas experimentalmente. A média aritmética eo modo são realmente precisa, e alterando os parâmetros ainda bastante agressiva parece não influenciá-los muito. Suponho que o comportamento da mediana já foi explicado.

Nota: não tome esses números para uma descrição matemática adequada da função. Usá-los para obter rapidamente uma imagem do que os olhares de distribuição gosta. Para qualquer outra coisa, eles são o suficiente para não preciso (embora possam ser mais preciso.

Talvez este seja útil para alguém.

Edit 2:

gráfico

Com base em apenas 991 valores. Eu poderia ter amontoados mais valores para ele, mas eles teriam distorcido o resultado. Esta amostra passa a ser bastante típico.

Editar 1:

aqui estão acima valores para apenas um dado sessenta e face, para comparação:

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

Note-se que estes valores são calculados, não experimental.

probabilidade ilimitada Composto é ... não-trivial. Eu estava indo para enfrentar o problema da mesma forma que James Curran, mas então eu vi do seu código fonte que poderia haver um terceiro conjunto de rolos, e uma quarta, e assim por diante. O problema pode ser resolvido, mas muito além maioria dos simuladores rolando die.

Há alguma razão especial que você precisa de um intervalo aleatório de -Inf para + Inf com uma curva tão complexo em torno de 1-60? Porque é que a curva do sino de 2D30 não é aceitável? Se você explicar suas necessidades, é provável que alguém poderia fornecer um algoritmo mais simples e mais limitada.

Bem, vamos ver. O segunda throw (que, por vezes, ser adicionado ou subtraído para o primeiro rolo) tem um bom facilmente curva de sino previsível em torno de 31. O primeiro rolo, é claro, é o problema.

Para o primeiro rolo, temos 900 combinações possíveis.

  • 50 combinações resultam em adicionar o segundo rolo.
  • 25 combinações resultam em subtrair o segundo rolo.
  • Deixando 825 combinações que correspondem a curva do sino do segundo rolo.

O conjunto de subtracção (pré-subtração) irá formar uma curva de sino na gama (27..35). A metade inferior do conjunto adicionando vai formar uma curva de sino na gama (2..10), enquanto a metade superior irá formar uma curva de sino no intervalo (52 ... 60)

Meu probablity é um pouco enferrujado, então eu não consigo descobrir os valores exatos para você, mas deve ficar claro que estas levam a valores previsíveis.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top