+% ------------------------------------------------------------------------------
+% $Id: Random.lhs,v 1.24 2001/02/28 00:01:03 qrczak Exp $
%
-% (c) The GRASP/AQUA Project, Glasgow University, 1995-99
+% (c) The University of Glasgow, 1995-2000
%
+\section[Random]{Module @Random@}
The June 1988 (v31 #6) issue of the Communications of the ACM has an
article by Pierre L'Ecuyer called, "Efficient and Portable Combined
, newStdGen
) where
-import CPUTime (getCPUTime)
-import PrelST
-import PrelRead
-import PrelIOBase
-import PrelNumExtra ( float2Double, double2Float )
-import PrelBase
-import PrelArr
-import Char ( isSpace, chr, ord )
-import Time (getClockTime, ClockTime(..))
-
+#ifndef __HUGS__
+import PrelGHC ( RealWorld )
+import PrelShow ( showSignedInt, showSpace )
+import PrelRead ( readDec )
+import PrelIOBase ( unsafePerformIO, stToIO )
+import PrelArr ( STRef, newSTRef, readSTRef, writeSTRef )
+import Time ( getClockTime, ClockTime(..) )
+#else
+import PrelPrim ( IORef
+ , newIORef
+ , readIORef
+ , writeIORef
+ , unsafePerformIO
+ )
+#endif
+
+import CPUTime ( getCPUTime )
+import Char ( isSpace, chr, ord )
\end{code}
\begin{code}
next = stdNext
split = stdSplit
+#ifdef __HUGS__
+instance Show StdGen where
+ showsPrec p (StdGen s1 s2) =
+ showsPrec p s1 .
+ showChar ' ' .
+ showsPrec p s2
+#else
instance Show StdGen where
showsPrec p (StdGen s1 s2) =
showSignedInt p s1 .
showSpace .
showSignedInt p s2
+#endif
instance Read StdGen where
- readsPrec p = \ r ->
+ readsPrec _p = \ r ->
case try_read r of
r@[_] -> r
_ -> [stdFromString r] -- because it shouldn't ever fail.
createStdGen :: Integer -> StdGen
createStdGen s
| s < 0 = createStdGen (-s)
- | otherwise = StdGen (toInt (s1+1)) (toInt (s2+1))
+ | otherwise = StdGen (fromInteger (s1+1)) (fromInteger (s2+1))
where
(q, s1) = s `divMod` 2147483562
s2 = q `mod` 2147483398
-- hah, so you thought you were saving cycles by using Float?
instance Random Float where
- randomR (a,b) g = randomIvalDouble (float2Double a, float2Double b) double2Float g
- random g = randomIvalDouble (0::Double,1) double2Float g
-
+ random g = randomIvalDouble (0::Double,1) realToFrac g
+ randomR (a,b) g = randomIvalDouble (realToFrac a, realToFrac b) realToFrac g
\end{code}
\begin{code}
+#ifdef __HUGS__
+mkStdRNG :: Integer -> IO StdGen
+mkStdRNG o = do
+ ct <- getCPUTime
+ return (createStdGen (ct + o))
+#else
mkStdRNG :: Integer -> IO StdGen
mkStdRNG o = do
ct <- getCPUTime
(TOD sec _) <- getClockTime
return (createStdGen (sec * 12345 + ct + o))
+#endif
randomIvalInteger :: (RandomGen g, Num a) => (Integer, Integer) -> g -> (a, g)
randomIvalInteger (l,h) rng
| l > h = randomIvalInteger (h,l) rng
- | otherwise = case (f n 1 rng) of (v, rng') -> (fromInteger (l + v `mod` (k+1)), rng')
+ | otherwise = case (f n 1 rng) of (v, rng') -> (fromInteger (l + v `mod` k), rng')
where
k = h - l + 1
b = 2147483561
let
(x,g') = next g
in
- f (n-1) (fromInt x + acc * b) g'
+ f (n-1) (fromIntegral x + acc * b) g'
randomIvalDouble :: (RandomGen g, Fractional a) => (Double, Double) -> (Double -> a) -> g -> (a, g)
randomIvalDouble (l,h) fromDouble rng
s2' = 40692 * (s2 - k' * 52774) - k' * 3791
s2'' = if s2' < 0 then s2' + 2147483399 else s2'
-stdSplit :: StdGen -> (StdGen, StdGen)
-stdSplit std@(StdGen s1 s2) = (std, unsafePerformIO (mkStdRNG (fromInt s1)))
-
+stdSplit :: StdGen -> (StdGen, StdGen)
+stdSplit std@(StdGen s1 s2)
+ = (left, right)
+ where
+ -- no statistical foundation for this!
+ left = StdGen new_s1 t2
+ right = StdGen t1 new_s2
+
+ new_s1 | s1 == 2147483562 = 1
+ | otherwise = s1 + 1
+
+ new_s2 | s2 == 1 = 2147483398
+ | otherwise = s2 - 1
+
+ StdGen t1 t2 = snd (next std)
\end{code}
\begin{code}
-global_rng :: MutableVar RealWorld StdGen
+#ifdef __HUGS__
+
+setStdGen :: StdGen -> IO ()
+setStdGen sgen = writeIORef theStdGen sgen
+
+getStdGen :: IO StdGen
+getStdGen = readIORef theStdGen
+
+theStdGen :: IORef StdGen
+theStdGen = unsafePerformIO (newIORef (createStdGen 0))
+
+#else
+
+global_rng :: STRef RealWorld StdGen
global_rng = unsafePerformIO $ do
rng <- mkStdRNG 0
- stToIO (newVar rng)
+ stToIO (newSTRef rng)
setStdGen :: StdGen -> IO ()
-setStdGen sgen = stToIO (writeVar global_rng sgen)
+setStdGen sgen = stToIO (writeSTRef global_rng sgen)
getStdGen :: IO StdGen
-getStdGen = stToIO (readVar global_rng)
+getStdGen = stToIO (readSTRef global_rng)
+
+#endif
+
newStdGen :: IO StdGen
newStdGen = do