mersenne-random-pure64 0.2 → 0.2.0.2
raw patch · 6 files changed
+63/−32 lines, 6 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
Files
- System/Random/Mersenne/Pure64.hs +13/−8
- System/Random/Mersenne/Pure64/Base.hsc +5/−5
- System/Random/Mersenne/Pure64/MTBlock.hs +11/−3
- TODO +5/−1
- mersenne-random-pure64.cabal +5/−5
- tests/Unit.hs +24/−10
System/Random/Mersenne/Pure64.hs view
@@ -7,11 +7,11 @@ -- Maintainer : Don Stewart <dons@galois.com> -- Stability : experimental -- Portability: CPP, FFI--- Tested with: GHC 6.8.2+-- Tested with: GHC 6.8.3 -- -- A purely functional binding 64 bit binding to the classic mersenne--- twister random number generator. This is more flexible than the --- impure 'mersenne-random' library, at the cost of being much slower.+-- twister random number generator. This is more flexible than the+-- impure 'mersenne-random' library, at the cost of being a bit slower. -- This generator is however, many times faster than System.Random, -- and yields high quality randoms with a long period. --@@ -79,24 +79,28 @@ -- generator and that 'Int'. The full 64 bits will be used on a 64 bit machine. randomInt :: PureMT -> (Int,PureMT) randomInt g = (fromIntegral i, g')- where (i,g') = randomWord64 g+ where (i, g') = randomWord64 g+{-# INLINE randomInt #-} -- | Yield a new 'Word' value from the generator, returning a new -- generator and that 'Word'. randomWord :: PureMT -> (Word,PureMT) randomWord g = (fromIntegral i, g')- where (i,g') = randomWord64 g+ where (i, g') = randomWord64 g+{-# INLINE randomWord #-} -- | Yield a new 'Int64' value from the generator, returning a new -- generator and that 'Int64'. randomInt64 :: PureMT -> (Int64,PureMT) randomInt64 g = (fromIntegral i, g')- where (i,g') = randomWord64 g+ where (i, g') = randomWord64 g+{-# INLINE randomInt64 #-} -- | Efficiently yield a new 53-bit precise 'Double' value, and a new generator. randomDouble :: PureMT -> (Double,PureMT) randomDouble g = (fromIntegral (i `div` 2048) / 9007199254740992, g')- where (i,g') = randomWord64 g+ where (i, g') = randomWord64 g+{-# INLINE randomDouble #-} -- | Yield a new 'Word64' value from the generator, returning a new -- generator and that 'Word64'.@@ -105,10 +109,11 @@ where mt | i < blockLen-1 = PureMT block (i+1) nxt | otherwise = mkPureMT nxt+{-# INLINE randomWord64 #-} -- | 'PureMT', a pure mersenne twister pseudo-random number generator ---data PureMT = PureMT !MTBlock !Int MTBlock+data PureMT = PureMT {-# UNPACK #-} !MTBlock {-# UNPACK #-} !Int MTBlock instance Show PureMT where show _ = show "<PureMT>"
System/Random/Mersenne/Pure64/Base.hsc view
@@ -7,11 +7,11 @@ -- Maintainer : Don Stewart <dons@galois.com> -- Stability : experimental -- Portability: CPP, FFI, EmptyDataDecls--- Tested with: GHC 6.8.2+-- Tested with: GHC 6.8.3 -- -- A purely functional binding 64 bit binding to the classic mersenne--- twister random number generator. This is more flexible than the --- impure 'mersenne-random' library, at the cost of being much slower.+-- twister random number generator. This is more flexible than the+-- impure 'mersenne-random' library, at the cost of being a bit slower. -- This generator is however, many times faster than System.Random, -- and yields high quality randoms with a long period. --@@ -41,7 +41,7 @@ c_genrand64_real2 :: Ptr MTState -> IO CDouble sizeof_MTState :: Int-sizeof_MTState = (#const (sizeof (struct mt_state_t))) -- 2504 bytes+sizeof_MTState = (# const sizeof (struct mt_state_t) ) -- 2504 bytes ------------------------------------------------------------------------ -- block based version:@@ -60,7 +60,7 @@ -- | size of an MT block, in bytes blockSize :: Int-blockSize = (# const sizeof(mt_block_struct) )+blockSize = (# const sizeof (mt_block_struct) ) ------------------------------------------------------------------------ -- model: (for testing purposes)
System/Random/Mersenne/Pure64/MTBlock.hs view
@@ -2,13 +2,19 @@ -------------------------------------------------------------------- -- | -- Module : System.Random.Mersenne.Pure64--- Copyright : Copyright (c) 2008, Bertram Felgenhauer <dons@galois.com>+-- Copyright : Copyright (c) 2008, Bertram Felgenhauer <int-e@gmx.de> -- License : BSD3 -- Maintainer : Don Stewart <dons@galois.com> -- Stability : experimental--- Portability: --- Tested with: GHC 6.8.2+-- Portability:+-- Tested with: GHC 6.8.3 --+-- A purely functional binding 64 bit binding to the classic mersenne+-- twister random number generator. This is more flexible than the+-- impure 'mersenne-random' library, at the cost of being a bit slower.+-- This generator is however, many times faster than System.Random,+-- and yields high quality randoms with a long period.+-- module System.Random.Mersenne.Pure64.MTBlock ( -- * Block type MTBlock,@@ -49,6 +55,7 @@ c_next_genrand64_block (blockAsPtr b) (blockAsPtr b) touch b return b+{-# NOINLINE seedBlock #-} -- | step: create a new MTBlock buffer from the previous one nextBlock :: MTBlock -> MTBlock@@ -58,6 +65,7 @@ touch b touch new return new+{-# NOINLINE nextBlock #-} -- stolen from GHC.ForeignPtr - make sure the argument is still alive. touch :: a -> IO ()
TODO view
@@ -7,7 +7,11 @@ This is actually an error on 32 bit machines - the default return type int is not large enough to hold the 64 bit result.++ This is fixed in ghc 6.9; the compiler emits its own prototypes. Check sequences are repeatable-check behaviour on 32 bits+Investigate slow conversion to Double (x86 at least)+ looking at the core, the conversion goes through toInteger and encodeFloat.+ That's a pity, because the FPU has an instruction for this purpose. profile/benchmark tests driver
mersenne-random-pure64.cabal view
@@ -1,6 +1,6 @@ name: mersenne-random-pure64-version: 0.2-homepage: http://code.haskell.org/~dons/code/mt19937-random+version: 0.2.0.2+homepage: http://code.haskell.org/~dons/code/mersenne-random-pure64/ synopsis: Generate high quality pseudorandom numbers purely using a Mersenne Twister description: The Mersenne twister is a pseudorandom number generator developed by@@ -14,7 +14,7 @@ This library provides a purely functional binding to the 64 bit classic mersenne twister, along with instances of RandomGen, so the generator can be used with System.Random. The generator should- typically be a few times faster than the default StdGen (but much+ typically be a few times faster than the default StdGen (but a tad slower than the impure 'mersenne-random' library based on SIMD instructions and destructive state updates. .@@ -24,9 +24,9 @@ copyright: (c) 2008. Don Stewart <dons@galois.com> author: Don Stewart maintainer: Don Stewart <dons@galois.com>-cabal-version: >= 1.2.0+cabal-version: >= 1.2.0 build-type: Simple-tested-with: GHC ==6.8.2+tested-with: GHC == 6.8.3 flag small_base description: Build with new smaller base library
tests/Unit.hs view
@@ -1,4 +1,7 @@-{-# OPTIONS -fbang-patterns -fglasgow-exts #-}+{-# LANGUAGE BangPatterns #-}+-- A basic correctness and performance test for mersenne-random-pure64.+--+-- Copyright (c) 2008, Don Stewart <dons@galois.com> import Control.Exception import Control.Monad@@ -36,11 +39,11 @@ ------------------------------------------------------------------------ -- calibrate s <- newMVar 0 :: IO (MVar Int)- putStr "Callibrating ... " >> hFlush stdout+ putStr "Calibrating ... " >> hFlush stdout tid <- forkIO $ do let go !i !g = do- let (!_,!g') = randomWord64 g+ let (!_, !g') = randomWord64 g x <- swapMVar s i x `seq` go (i+1) g' go 0 g@@ -48,7 +51,7 @@ threadDelay (1000 * 1000) killThread tid lim <- readMVar s -- 1 sec worth of generation- putStrLn $ "done. Using N="++ show lim+ putStrLn $ "done. Using N=" ++ show lim time $ do let m = 2*lim@@ -56,7 +59,7 @@ hFlush stdout equivalent g m - speed lim + speed lim return () @@ -67,8 +70,8 @@ i' <- c_genrand64_int64_unsafe d' <- c_genrand64_real2_unsafe - let (i,g') = randomWord64 g- (d,g'') = randomDouble g'+ let (i, g') = randomWord64 g+ (d, g'') = randomDouble g' if i == fromIntegral i' && d == realToFrac d' then do when (n `rem` 500000 == 0) $ putChar '.' >> hFlush stdout@@ -93,7 +96,7 @@ go !g !n !acc | n >= lim = acc | otherwise =- let (a,g') = Old.random g+ let (a, g') = Old.random g in go g' (n+1) (if a > acc then a else acc) print (go g 0 0) @@ -121,6 +124,17 @@ print (go g 0 0) time $ do+ putStrLn $ "System.Random.Mersenne.Pure generating Double"+ let g = pureMT 5+ let go :: PureMT -> Int -> Double -> Double+ go !g !n !acc+ | n >= lim = acc+ | otherwise =+ let (a, g') = randomDouble g+ in go g' (n+1) (if a > acc then a else acc)+ print (go g 0 0)++ time $ do putStrLn $ "System.Random.Mersenne.Pure (unique state)" c_init_genrand64_unsafe 5 let go :: Int -> Int -> IO Int@@ -129,7 +143,7 @@ | otherwise = do a' <- c_genrand64_int64_unsafe let a = fromIntegral a'- go (n+1::Int) (if a > acc then a else acc)+ go (n+1) (if a > acc then a else acc) print =<< go 0 0 time $ do@@ -141,7 +155,7 @@ | n >= lim = return acc | otherwise = do a <- Unsafe.random g- go (n+1::Int) (if a > acc then a else acc)+ go (n+1) (if a > acc then a else acc) print =<< go 0 0