Search code examples
randomelm

Elm Random generator, timestamp as initialSeed


I made a simple code showing how much time a Random.bool appears to be True or False every milliseconds. The generator produced booleans with the current timestamp as seed.

I would expect the booleans will change almost each iterations but i get an unexpected big series of True or False.

What's happening so ?

Edit: I have better results with boolRandom (time*time).

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

Here in 0.16 with 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

Solution

  • Do not use the current time as a random seed, because of exactly the problem you are experiencing. You should call Random.initialSeed exactly once in your program (that means one invocation, not in one function that's called N times). Whenever you generate a random number, it gives you a new seed, and you should keep the seed in the Stat type instead of the time. Then:

    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}
    

    You can also delete boolRandom - throwing away the new seed with fst is bad!

    So, how do you get a good random seed in the first place? The current time is actually a poor choice since it's not uniformly distributed. Instead, evaluate Math.floor(Math.random()*0xFFFFFFFF) in your JS console of choice and paste in the result. To get a program that varies each run, pass the result of evaluating that expression in through port.