1 {- 2 This module implements a (good) random number generator. 3 4 The June 1988 (v31 #6) issue of the Communications of the ACM has an 5 article by Pierre L'Ecuyer called, "Efficient and Portable Combined 6 Random Number Generators". Here is the Portable Combined Generator of 7 L'Ecuyer for 32-bit computers. It has a period of roughly 2.30584e18. 8 9 Transliterator: Lennart Augustsson 10 11 Modified 10/11/97 by Alastair Reid: 12 Added random and randomIO based on GHC's implementation of the 13 standard Random library. 14 15 Modified 04/02/99 by Erik van der Meer: 16 Removed randomIO and renamed the module. 17 Quick fix because GHC won't compile my SET Circuit Simulator 18 when I import this module, so I included it. 19 20 Comes from the Hugs 1.4 distribution. 21 -} 22 23 module RandomFix(random) where 24 25 26 random :: (Integer, Integer) -> Integer -> [Integer] 27 random (l, h) s = 28 if l > h then error "Random.random: Empty interval" else 29 if s < 0 then random (l, h) (-s) else 30 let (q, s1) = s `divMod` 2147483562 31 s2 = q `mod` 2147483398 32 k = h-l + 1 33 b = 2147483561 34 n = iLogBase b k 35 f is = let (xs, is') = splitAt n is 36 in foldr (\ i r -> fromIntegral i + r * b) 0 xs `mod` k + l : f is' 37 in f (randomInts (fromIntegral (s1+1)) (fromIntegral (s2+1))) 38 39 iLogBase b i = if i < b then 1 else 1 + iLogBase b (i `div` b) 40 41 -- Use seeds s1 in 1..2147483562 and s2 in 1..2147483398 to generate 42 -- an infinite list of random Ints. 43 randomInts :: Int -> Int -> [Int] 44 randomInts s1 s2 = 45 if 1 <= s1 && s1 <= 2147483562 then 46 if 1 <= s2 && s2 <= 2147483398 then 47 rands s1 s2 48 else 49 error "randomInts: Bad second seed." 50 else 51 error "randomInts: Bad first seed." 52 53 rands :: Int -> Int -> [Int] 54 rands s1 s2 = z' : rands s1'' s2'' 55 where z' = if z < 1 then z + 2147483562 else z 56 z = s1'' - s2'' 57 58 k = s1 `quot` 53668 59 s1' = 40014 * (s1 - k * 53668) - k * 12211 60 s1'' = if s1' < 0 then s1' + 2147483563 else s1' 61 62 k' = s2 `quot` 52774 63 s2' = 40692 * (s2 - k' * 52774) - k' * 3791 64 s2'' = if s2' < 0 then s2' + 2147483399 else s2' 65