{-# LANGUAGE ScopedTypeVariables, BangPatterns #-} module Random (randomInts) where import qualified Data.Vector.Unboxed.Mutable as MV import qualified Data.Vector.Unboxed as V import Data.Vector.Unboxed (Vector) import qualified Data.Vector.Generic as G import Data.Word -- | Use the "minimal standard" Lehmer generator to quickly generate some random -- numbers with reasonable statistical properties. By "reasonable" we mean good -- enough for games and test data, but not cryptography or anything where the -- quality of the randomness really matters. -- -- From "Random Number Generators: Good ones are hard to find" -- Stephen K. Park and Keith W. Miller. -- Communications of the ACM, Oct 1988, Volume 31, Number 10. -- randomInts :: Int -- Length of vector. -> Int -- Minumum value in output. -> Int -- Maximum value in output. -> Int -- Random seed. -> Vector Int -- Vector of random numbers. randomInts !len !valMin' !valMax' !seed' = let -- a magic number (don't change it) multiplier :: Word64 multiplier = 16807 -- a merzenne prime (don't change it) modulus :: Word64 modulus = 2^31 - 1 -- if the seed is 0 all the numbers in the sequence are also 0. seed | seed' == 0 = 1 | otherwise = seed' !valMin = fromIntegral valMin' !valMax = fromIntegral valMax' + 1 !range = valMax - valMin {-# INLINE f #-} f x = multiplier * x `mod` modulus in G.create $ do vec <- MV.new len let go !ix !x | ix == len = return () | otherwise = do let x' = f x MV.write vec ix $fromIntegral $ (x `mod` range) + valMin go (ix + 1) x' go 0 (f $ fromIntegral seed) return vec