2 % (c) The GRASP/AQUA Project, Glasgow University, 1995-99
6 The June 1988 (v31 #6) issue of the Communications of the ACM has an
7 article by Pierre L'Ecuyer called, "Efficient and Portable Combined
8 Random Number Generators". Here is the Portable Combined Generator of
9 L'Ecuyer for 32-bit computers. It has a period of roughly 2.30584e18.
11 Transliterator: Lennart Augustsson
13 sof 1/99 - code brought (kicking and screaming) into the new Random
19 RandomGen(next, split)
22 , Random ( random, randomR,
31 import CPUTime (getCPUTime)
35 import PrelNumExtra ( float2Double, double2Float )
38 import Char ( isSpace, chr, ord )
39 import Time (getClockTime, ClockTime(..))
44 class RandomGen g where
54 instance RandomGen StdGen where
58 instance Show StdGen where
59 showsPrec p (StdGen s1 s2) =
64 instance Read StdGen where
68 _ -> [(unsafePerformIO mkStdRNG,r)] -- because it shouldn't ever fail.
71 (s1, r1) <- readDec (dropWhile isSpace r)
72 (s2, r2) <- readDec (dropWhile isSpace r1)
73 return (StdGen s1 s2, r2)
78 mkStdGen :: Int -> StdGen -- why not Integer ?
80 | s < 0 = mkStdGen (-s)
81 | otherwise = StdGen (s1+1) (s2+1)
83 (q, s1) = s `divMod` 2147483562
84 s2 = q `mod` 2147483398
86 createStdGen :: Integer -> StdGen
88 | s < 0 = createStdGen (-s)
89 | otherwise = StdGen (toInt (s1+1)) (toInt (s2+1))
91 (q, s1) = s `divMod` 2147483562
92 s2 = q `mod` 2147483398
98 -- Q: do all of these merit class membership?
100 randomR :: RandomGen g => (a,a) -> g -> (a,g)
101 random :: RandomGen g => g -> (a, g)
103 randomRs :: RandomGen g => (a,a) -> g -> [a]
104 randoms :: RandomGen g => g -> [a]
106 randomRIO :: (a,a) -> IO a
109 randoms g = x : randoms g' where (x,g') = random g
110 randomRs ival g = x : randomRs ival g' where (x,g') = randomR ival g
112 randomIO = getStdRandom random
113 randomRIO range = getStdRandom (randomR range)
118 instance Random Int where
119 randomR (a,b) g = randomIvalInteger (toInteger a, toInteger b) g
120 random g = randomR (minBound,maxBound) g
122 instance Random Char where
124 case (randomIvalInteger (toInteger (ord a), toInteger (ord b)) g) of
126 random g = randomR (minBound,maxBound) g
128 instance Random Bool where
130 case (randomIvalInteger (toInteger (bool2Int a), toInteger (bool2Int b)) g) of
131 (x, g) -> (int2Bool x, g)
139 random g = randomR (minBound,maxBound) g
141 instance Random Integer where
142 randomR ival g = randomIvalInteger ival g
143 random g = randomR (toInteger (minBound::Int), toInteger (maxBound::Int)) g
145 instance Random Double where
146 randomR ival g = randomIvalDouble ival id g
147 random g = randomR (0::Double,1) g
149 -- hah, so you thought you were saving cycles by using Float?
150 instance Random Float where
151 randomR (a,b) g = randomIvalDouble (float2Double a, float2Double b) double2Float g
152 random g = randomIvalDouble (0::Double,1) double2Float g
158 mkStdRNG :: IO StdGen
161 (TOD sec _) <- getClockTime
162 return (createStdGen (sec * 12345 + ct))
164 randomIvalInteger :: (RandomGen g, Num a) => (Integer, Integer) -> g -> (a, g)
165 randomIvalInteger (l,h) rng
166 | l > h = randomIvalInteger (h,l) rng
167 | otherwise = case (f n 1 rng) of (v, rng') -> (fromInteger (l + v `mod` (k+1)), rng')
178 f (n-1) (fromInt x + acc * b) g'
180 randomIvalDouble :: (RandomGen g, Fractional a) => (Double, Double) -> (Double -> a) -> g -> (a, g)
181 randomIvalDouble (l,h) fromDouble rng
182 | l > h = randomIvalDouble (h,l) fromDouble rng
184 case (randomIvalInteger (toInteger (minBound::Int), toInteger (maxBound::Int)) rng) of
190 (fromIntegral (x::Int) * 4.6566130638969828e-10)
191 -- magic number stolen from old HBC code (Random.randomDoubles.)
195 iLogBase :: Integer -> Integer -> Integer
196 iLogBase b i = if i < b then 1 else 1 + iLogBase b (i `div` b)
198 rand1 :: StdGen -> (Int, StdGen)
199 rand1 (StdGen s1 s2) = (z', StdGen s1'' s2'')
200 where z' = if z < 1 then z + 2147483562 else z
204 s1' = 40014 * (s1 - k * 53668) - k * 12211
205 s1'' = if s1' < 0 then s1' + 2147483563 else s1'
208 s2' = 40692 * (s2 - k' * 52774) - k' * 3791
209 s2'' = if s2' < 0 then s2' + 2147483399 else s2'
211 splitStdGen :: StdGen -> (StdGen, StdGen)
212 splitStdGen std@(StdGen s1 s2) = (std, StdGen new_s1 new_s2)
214 -- simple in the extreme..
216 | s1 == 2147483562 = 1
220 | s2 == 1 = 2147483398
229 global_rng :: MutableVar RealWorld StdGen
230 global_rng = unsafePerformIO $ do
234 setStdGen :: StdGen -> IO ()
235 setStdGen sgen = stToIO (writeVar global_rng sgen)
237 getStdGen :: IO StdGen
238 getStdGen = stToIO (readVar global_rng)
240 newStdGen :: IO StdGen
243 let (a,b) = split rng
247 getStdRandom :: (StdGen -> (a,StdGen)) -> IO a
250 let (v, new_rng) = f rng