random 1.0.0.3 → 1.0.1.0
raw patch · 2 files changed
+146/−34 lines, 2 filesnew-uploader
Files
- System/Random.hs +136/−30
- random.cabal +10/−4
System/Random.hs view
@@ -1,3 +1,7 @@+#if __GLASGOW_HASKELL__ >= 701+{-# LANGUAGE Trustworthy #-}+#endif+ ----------------------------------------------------------------------------- -- | -- Module : System.Random@@ -33,6 +37,8 @@ -- ----------------------------------------------------------------------------- +#include "MachDeps.h"+ module System.Random ( @@ -40,8 +46,12 @@ -- * Random number generators - RandomGen(next, split, genRange)-+#ifdef ENABLE_SPLITTABLEGEN+ RandomGen(next, genRange)+ , SplittableGen(split)+#else+ RandomGen(next, genRange, split)+#endif -- ** Standard random number generators , StdGen , mkStdGen@@ -67,7 +77,10 @@ import Prelude +import Data.Bits import Data.Int+import Data.Word+import Foreign.C.Types #ifdef __NHC__ import CPUTime ( getCPUTime )@@ -101,7 +114,7 @@ -- | The class 'RandomGen' provides a common interface to random number -- generators. ----- Minimal complete definition: 'next' and 'split'.+-- Minimal complete definition: 'next'. class RandomGen g where @@ -110,14 +123,6 @@ -- and a new generator. next :: g -> (Int, g) - -- |The 'split' operation allows one to obtain two distinct random number- -- generators. This is very useful in functional programs (for example, when- -- passing a random number generator down to recursive calls), but very- -- little work has been done on statistically robust implementations of- -- 'split' (["System.Random\#Burton", "System.Random\#Hellekalek"]- -- are the only examples we know of).- split :: g -> (g, g)- -- |The 'genRange' operation yields the range of values returned by -- the generator. --@@ -140,6 +145,19 @@ -- default method genRange _ = (minBound, maxBound) +#ifdef ENABLE_SPLITTABLEGEN+-- | The class 'SplittableGen' proivides a way to specify a random number+-- generator that can be split into two new generators.+class SplittableGen g where+#endif+ -- |The 'split' operation allows one to obtain two distinct random number+ -- generators. This is very useful in functional programs (for example, when+ -- passing a random number generator down to recursive calls), but very+ -- little work has been done on statistically robust implementations of+ -- 'split' (["System.Random\#Burton", "System.Random\#Hellekalek"]+ -- are the only examples we know of).+ split :: g -> (g, g)+ {- | The 'StdGen' instance of 'RandomGen' has a 'genRange' of at least 30 bits. @@ -171,9 +189,13 @@ instance RandomGen StdGen where next = stdNext- split = stdSplit genRange _ = stdRange +#ifdef ENABLE_SPLITTABLEGEN+instance SplittableGen StdGen where+#endif+ split = stdSplit+ instance Show StdGen where showsPrec p (StdGen s1 s2) = showsPrec p s1 . @@ -210,10 +232,11 @@ mkStdGen s = mkStdGen32 $ fromIntegral s mkStdGen32 :: Int32 -> StdGen-mkStdGen32 s- | s < 0 = mkStdGen32 (-s)- | otherwise = StdGen (s1+1) (s2+1)+mkStdGen32 sMaybeNegative = StdGen (s1+1) (s2+1) where+ -- We want a non-negative number, but we can't just take the abs+ -- of sMaybeNegative as -minBound == minBound.+ s = sMaybeNegative .&. maxBound (q, s1) = s `divMod` 2147483562 s2 = q `mod` 2147483398 @@ -271,14 +294,49 @@ randomIO = getStdRandom random -instance Random Int where- randomR (a,b) g = randomIvalInteger (toInteger a, toInteger b) g- random g = randomR (minBound,maxBound) g+instance Random Integer where+ randomR ival g = randomIvalInteger ival g+ random g = randomR (toInteger (minBound::Int), toInteger (maxBound::Int)) g +instance Random Int where randomR = randomIvalIntegral; random = randomBounded+instance Random Int8 where randomR = randomIvalIntegral; random = randomBounded+instance Random Int16 where randomR = randomIvalIntegral; random = randomBounded+instance Random Int32 where randomR = randomIvalIntegral; random = randomBounded+instance Random Int64 where randomR = randomIvalIntegral; random = randomBounded++#ifndef __NHC__+-- Word is a type synonym in nhc98.+instance Random Word where randomR = randomIvalIntegral; random = randomBounded+#endif+instance Random Word8 where randomR = randomIvalIntegral; random = randomBounded+instance Random Word16 where randomR = randomIvalIntegral; random = randomBounded+instance Random Word32 where randomR = randomIvalIntegral; random = randomBounded+instance Random Word64 where randomR = randomIvalIntegral; random = randomBounded++instance Random CChar where randomR = randomIvalIntegral; random = randomBounded+instance Random CSChar where randomR = randomIvalIntegral; random = randomBounded+instance Random CUChar where randomR = randomIvalIntegral; random = randomBounded+instance Random CShort where randomR = randomIvalIntegral; random = randomBounded+instance Random CUShort where randomR = randomIvalIntegral; random = randomBounded+instance Random CInt where randomR = randomIvalIntegral; random = randomBounded+instance Random CUInt where randomR = randomIvalIntegral; random = randomBounded+instance Random CLong where randomR = randomIvalIntegral; random = randomBounded+instance Random CULong where randomR = randomIvalIntegral; random = randomBounded+instance Random CPtrdiff where randomR = randomIvalIntegral; random = randomBounded+instance Random CSize where randomR = randomIvalIntegral; random = randomBounded+instance Random CWchar where randomR = randomIvalIntegral; random = randomBounded+instance Random CSigAtomic where randomR = randomIvalIntegral; random = randomBounded+instance Random CLLong where randomR = randomIvalIntegral; random = randomBounded+instance Random CULLong where randomR = randomIvalIntegral; random = randomBounded+instance Random CIntPtr where randomR = randomIvalIntegral; random = randomBounded+instance Random CUIntPtr where randomR = randomIvalIntegral; random = randomBounded+instance Random CIntMax where randomR = randomIvalIntegral; random = randomBounded+instance Random CUIntMax where randomR = randomIvalIntegral; random = randomBounded+ instance Random Char where randomR (a,b) g = - case (randomIvalInteger (toInteger (ord a), toInteger (ord b)) g) of- (x,g') -> (chr x, g')+ case (randomIvalInteger (toInteger (ord a), toInteger (ord b)) g) of+ (x,g') -> (chr x, g') random g = randomR (minBound,maxBound) g instance Random Bool where@@ -295,26 +353,70 @@ int2Bool _ = True random g = randomR (minBound,maxBound) g- -instance Random Integer where- randomR ival g = randomIvalInteger ival g- random g = randomR (toInteger (minBound::Int), toInteger (maxBound::Int)) g +{-# INLINE randomRFloating #-}+randomRFloating :: (Num a, Ord a, Random a, RandomGen g) => (a, a) -> g -> (a, g)+randomRFloating (l,h) g + | l>h = randomRFloating (h,l) g+ | otherwise = let (coef,g') = random g in + (l + coef * (h-l), g')+ instance Random Double where- randomR ival g = randomIvalDouble ival id g- random g = randomR (0::Double,1) g- --- hah, so you thought you were saving cycles by using Float?+ randomR = randomRFloating+ random rng = + case random rng of + (x,rng') -> + -- We use 53 bits of randomness corresponding to the 53 bit significand:+ ((fromIntegral (mask53 .&. (x::Int64)) :: Double) + / fromIntegral twoto53, rng')+ where + twoto53 = (2::Int64) ^ (53::Int64)+ mask53 = twoto53 - 1+ instance Random Float where- random g = randomIvalDouble (0::Double,1) realToFrac g- randomR (a,b) g = randomIvalDouble (realToFrac a, realToFrac b) realToFrac g+ randomR = randomRFloating+ random rng = + -- TODO: Faster to just use 'next' IF it generates enough bits of randomness. + case random rng of + (x,rng') -> + -- We use 24 bits of randomness corresponding to the 24 bit significand:+ ((fromIntegral (mask24 .&. (x::Int32)) :: Float) + / fromIntegral twoto24, rng')+ -- Note, encodeFloat is another option, but I'm not seeing slightly+ -- worse performance with the following [2011.06.25]:+-- (encodeFloat rand (-24), rng')+ where+ mask24 = twoto24 - 1+ twoto24 = (2::Int32) ^ (24::Int32) +-- CFloat/CDouble are basically the same as a Float/Double:+instance Random CFloat where+ randomR = randomRFloating+ random rng = case random rng of + (x,rng') -> (realToFrac (x::Float), rng')++instance Random CDouble where+ randomR = randomRFloating+ -- A MYSTERY:+ -- Presently, this is showing better performance than the Double instance:+ -- (And yet, if the Double instance uses randomFrac then its performance is much worse!)+ random = randomFrac+ -- random rng = case random rng of + -- (x,rng') -> (realToFrac (x::Double), rng')+ mkStdRNG :: Integer -> IO StdGen mkStdRNG o = do ct <- getCPUTime (sec, psec) <- getTime return (createStdGen (sec * 12345 + psec + ct + o)) +randomBounded :: (RandomGen g, Random a, Bounded a) => g -> (a, g)+randomBounded = randomR (minBound, maxBound)++-- The two integer functions below take an [inclusive,inclusive] range.+randomIvalIntegral :: (RandomGen g, Integral a) => (a, a) -> g -> (a, g)+randomIvalIntegral (l,h) = randomIvalInteger (toInteger l, toInteger h)+ randomIvalInteger :: (RandomGen g, Num a) => (Integer, Integer) -> g -> (a, g) randomIvalInteger (l,h) rng | l > h = randomIvalInteger (h,l) rng@@ -330,6 +432,10 @@ (x,g') = next g in f (n' - 1) (fromIntegral x + acc * b) g'++-- The continuous functions on the other hand take an [inclusive,exclusive) range.+randomFrac :: (RandomGen g, Fractional a) => g -> (a, g)+randomFrac = randomIvalDouble (0::Double,1) realToFrac randomIvalDouble :: (RandomGen g, Fractional a) => (Double, Double) -> (Double -> a) -> g -> (a, g) randomIvalDouble (l,h) fromDouble rng
random.cabal view
@@ -1,8 +1,11 @@ name: random-version: 1.0.0.3+version: 1.0.1.0++-- 1.0.1.0 -- bump for bug fixes, but no SplittableGen yet+ license: BSD3 license-file: LICENSE-maintainer: libraries@haskell.org+maintainer: rrnewton@gmail.com bug-reports: http://hackage.haskell.org/trac/ghc/newticket?component=libraries/random synopsis: random number library category: System@@ -11,13 +14,16 @@ build-type: Simple Cabal-Version: >= 1.6 ++ Library exposed-modules: System.Random extensions: CPP+ GHC-Options: -O2 build-depends: base >= 3 && < 5, time source-repository head- type: darcs- location: http://darcs.haskell.org/packages/random+ type: git+ location: http://darcs.haskell.org/packages/random.git/