AC-Random-0.1: Random/MWC/Primitive.hs
{- |
This module contains the raw random number generator algorithm.
Usually you would import "Random.MWC.Pure" for a more convinient
API.
-}
module Random.MWC.Primitive
(
-- * Random seed
Seed (), seed,
-- * Random number generation
next_word,
)
where
import Data.Bits
import Data.Word
-- | An immutable random seed value for the PRNG.
data Seed =
Seed
{
word1, word2, word3, word4, carry :: {-# UNPACK #-} !Word32
}
deriving (Eq, Ord)
magic = 0xFFFFFF4E :: Word64
seed0 =
Seed
0x8DC106A9
0x42FE9BA1
0x0284BC8A
0xABA48CE2
0x5935B28D
{- |
Create a new random seed value from the supplied list of 'Word32'
values. If the list is empty, return a default, hard-coded value.
Otherwise, every element of the list affects the result. The list
/must/ be finite; the function will loop forever othewise.
-}
seed :: [Word32] -> Seed
seed = foldr f seed0
where
f i (Seed w1 w2 w3 w4 c) = Seed w2 w3 w4 (w1 `xor` i) c
{- |
Given an initial 'Seed' value, return a random 'Word32' and a new
'Seed' value.
The 'Word32' value is chosen psuedo-randomly (i.e., the same 'Seed'
is guaranteed to always yield the same choice) with uniform
distribution (i.e., all possibilities equally likely) over the
complete range from 0x00000000 to 0xFFFFFFFF inclusive.
-}
next_word :: Seed -> (Word32, Seed)
next_word (Seed w1 w2 w3 w4 c) =
let
new = magic * (fromIntegral w4) + (fromIntegral c)
lo = fromIntegral $ new
hi = fromIntegral $ new `shift` (-32)
in (lo, Seed lo w1 w2 w3 hi)