2015-11-22 1 views
2

J'ai créé un code simple indiquant combien de temps un Random.bool semble être vrai ou faux toutes les millisecondes. Le générateur a généré des booléens avec l'horodatage actuel en tant que graine.Elm Générateur aléatoire, horodatage initialSeed

Je m'attendrais à ce que les booléens changent presque chaque itération mais j'obtiens une grande série inattendue de Vrai ou de Faux.

Que se passe-t-il donc?

Editer: J'ai de meilleurs résultats avec boolRandom (time * time).

Live preview on share-elm 0.15, with Random.int 0 1

Ici, en 0.16 avec Random.bool:

import Signal 
import Random 
import Time exposing (Time) 
import Graphics.Element exposing (Element, show, flow, down) 

type alias Stat = {time: Time, true: Int, false: Int} 

newStat: Stat 
newStat = Stat 0 0 0 

scene : Stat -> Element 
scene stat = 
    flow down 
    [ "Time: "++(toString stat.time) |> show 
    , "True: "++(toString stat.true) |> show 
    , "False: "++(toString stat.false) |> show 
    ] 

boolRandom : Time -> Bool 
boolRandom time = 
    Random.generate Random.bool (Random.initialSeed (round time)) |> fst 

updateData : Time -> Stat -> Stat 
updateData time stat = 
    if boolRandom time == True 
    then {stat | time = time , true = stat.true+1} 
    else {stat | time = time , false = stat.false+1} 

updateEvery : Signal Stat 
updateEvery = 
    Signal.foldp updateData newStat (Time.every Time.millisecond) 

main = Signal.map scene updateEvery 

Répondre

4

Ne pas utiliser l'heure actuelle comme une graine aléatoire, en raison de exactement le problème que vous rencontrez. Vous devez appeler Random.initialSeed exactement une fois dans votre programme (cela signifie une invocation, pas dans une fonction appelée N fois). Chaque fois que vous générez un nombre aléatoire, il vous donne une nouvelle graine, et vous devriez garder la graine dans le type Stat au lieu de l'heure. Puis:

updateData : Time -> Stat -> Stat 
updateData time stat = 
    let (bool, seed) = Random.generate Random.bool stat.seed 
    in if bool 
    then {stat | seed = seed , true = stat.true+1} 
    else {stat | seed = seed , false = stat.false+1} 

Vous pouvez également supprimer boolRandom - jeter la nouvelle graine avec fst est mauvais! Alors, comment obtenez-vous une bonne graine aléatoire en premier lieu? L'heure actuelle est en fait un mauvais choix car elle n'est pas uniformément distribuée. Au lieu de cela, évaluez Math.floor(Math.random()*0xFFFFFFFF) dans votre console JS de votre choix et collez le résultat. Pour obtenir un programme qui varie à chaque exécution, passez le résultat de l'évaluation de cette expression dans le port.

0

En cas de personnes ont besoin d'une solution de travail avec une graine initiale statique:

import Signal 
import Random exposing (Seed) 
import Time exposing (Time) 
import Graphics.Element exposing (Element, show, flow, down) 

type alias Stat = {time: Time, seed: Seed, true: Int, false: Int} 

newStat: Stat 
newStat = Stat 0 (Random.initialSeed 123456789) 0 0 

scene : Stat -> Element 
scene stat = 
    flow down 
    [ "Time: "++(toString stat.time) |> show 
    , "True: "++(toString stat.true) |> show 
    , "False: "++(toString stat.false) |> show 
    ] 

updateData : Time -> Stat -> Stat 
updateData time stat = 
    let (bool, seed) = Random.generate Random.bool stat.seed 
    in if bool 
    then {stat | time = time, seed = seed , true = stat.true+1} 
    else {stat | time = time, seed = seed , false = stat.false+1} 

updateEvery : Signal Stat 
updateEvery = 
    Signal.foldp updateData newStat (Time.every Time.millisecond) 

main = Signal.map scene updateEvery