
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