[Haskell-cafe] Re: True Random Numbers

mokus at deepbondi.net mokus at deepbondi.net
Thu Apr 8 10:06:41 EDT 2010


> Is there a way to get multiple random numbers without having to
> replicateM?
>
> While comparing the random-fu interface with Control.Monad.Random (both
> using StdGen), I noticed that while performance is comparable, using
> getRandomRs to get a list of random numbers is a lot faster than
> replicating uniform (or getRandomR for that matter). I don't know if
> this kind of speed gain makes sense for random-fu though.

I have been attempting to replicate this.  What sort of a performance
difference are you seeing, and are you using the hackage-released version
of random-fu or the darcs one?  The darcs release is, overall, a fair bit
faster than the current hackage release.  Depending on the particular way
that I sample my RVars (eg, replicateM n (sample ...) vs sample
(replicateM n ...)), I am seeing the random-fu version of my little
benchmark run anywhere from 30% faster to 25% slower than
Control.Monad.Random.getRandomRs (for 64000 uniform Double samples).  The
same benchmark using random-fu-0.0.3.2 shows it consistently about 33%
slower than getRandomRs.

In case you're interested, this is the (criterion) benchmark I used (with
count = 64000, and in the first bgroup 'src' is an "IORef StdGen"):

> [ bgroup "replicateM"
>     [ bench "randomRIO" $ do
>         xs <- replicateM count (randomRIO (10,50) :: IO Double)
>         sum xs `seq` return ()
>
>     , bench "uniform A" $ do
>         xs <- replicateM count
>                   (sampleFrom src (uniform 10 50) :: IO Double)
>         sum xs `seq` return ()
>     , bench "uniform B" $ do
>         xs <- sampleFrom src
>                   (replicateM count (uniform 10 50)) :: IO [Double]
>         sum xs `seq` return ()
>     ]
>
> , bgroup "pure StdGen"
>     [ bench "getRandomRs" $ do
>         src <- newStdGen
>         let (xs, _) = CMR.runRand (CMR.getRandomRs (10,50)) src
>         sum (take count xs :: [Double]) `seq` return ()
>     , bench "RVarT, State - sample replicateM" $ do
>         src <- newStdGen
>         let (xs, _) = runState
>                   (sample (replicateM count (uniform 10 50))) src
>         sum (xs :: [Double]) `seq` return ()
>     , bench "RVarT, State - replicateM sample" $ do
>         src <- newStdGen
>         let (xs, _) = runState
>                   (replicateM count (sample (uniform 10 50))) src
>         sum (xs :: [Double]) `seq` return ()
>     ]

If the problem is worse than this benchmark indicates, or if this
benchmark shows radically different results on a different platform (I'm
running on Mac  OS 10.6 with GHC 6.12.1), I'd love to hear about it.  I
could certainly imagine cases where the choice of monad in which to sample
makes things quite slow.  In the above case, I was using IO in the first
bgroup and State StdGen in the second.

As for whether an optimization like getRandomRs would benefit the
random-fu library:  I have tried a few different times to implement list
or vector primitives and the corresponding high-level interfaces for
sampling many variables at once, but have not yet come up with a version
that actually made anything faster.  I'm more than happy to accept patches
if someone comes up with one, though! ;)

-- James



More information about the Haskell-Cafe mailing list