Skip to content

Instantly share code, notes, and snippets.

@rblaze
Created August 1, 2011 15:40
Show Gist options
  • Save rblaze/1118378 to your computer and use it in GitHub Desktop.
Save rblaze/1118378 to your computer and use it in GitHub Desktop.
32-bit Mersenne Twister in Haskell
import Data.Bits
import Data.Word
import System.Random
mtN = 624
mtM = 397
data MersenneTwister = MersenneTwister [Word32] Int
deriving Show
getMT :: Word32 -> MersenneTwister
mtNext :: [Word32] -> Int -> (Int, MersenneTwister)
instance RandomGen MersenneTwister where
next (MersenneTwister cache i) = mtNext cache i
split g = (g, g)
getMT init = MersenneTwister (scanl mtInitStep init [1..mtN-1]) mtN
where mtInitStep :: Word32 -> Int -> Word32
mtInitStep prev i = 1812433253 * (prev `xor` (prev `shiftR` 30)) + fromIntegral i
mtNext cache i
| i < mtN = (shuffle (cache !! i), MersenneTwister cache (i + 1))
| otherwise = (shuffle (head newcache), MersenneTwister newcache 1)
where shuffle :: Word32 -> Int
shuffle y = fromIntegral v
where y1 = y `xor` (y `shiftR` 11)
y2 = y1 `xor` ((y1 `shiftL` 7) .&. 0x9d2c5680)
y3 = y2 `xor` ((y2 `shiftL` 15) .&. 0xefc60000)
y4 = y3 `xor` (y3 `shiftR` 18)
v = toInteger y4 + toInteger (minBound :: Int)
newcache = mtNextState cache
mtNextState :: [Word32] -> [Word32]
mtNextState state = allbutlast ++ [last]
where part1 = map (setState1 state) [0 .. mtN - mtM - 1]
allbutlast = makeall state part1 [mtN - 2, mtN - 3 .. mtN - mtM]
makeall s ns [] = ns
makeall s ns (i:is) = rs ++ [value]
where value = setState2 s rs i
rs = makeall s ns is
last = setState3 state allbutlast
setState1 :: [Word32] -> Int -> Word32
setState1 state i = (state !! (i + mtM)) `xor` twist (state !! i) (state !! (i + 1))
setState2 :: [Word32] -> [Word32] -> Int -> Word32
setState2 state newstate i = (newstate !! (i + mtM - mtN)) `xor` twist (state !! i) (state !! (i + 1))
setState3 :: [Word32] -> [Word32] -> Word32
setState3 state newstate = (newstate !! (mtM - 1)) `xor` twist (state !! (mtN - 1)) (head newstate)
mixbits :: Word32 -> Word32 -> Word32
mixbits u v = (u .&. 0x80000000) .|. (v .&. 0x7fffffff)
twist :: Word32 -> Word32 -> Word32
twist u v = (mixbits u v `shiftR` 1) `xor` n
where n
| v .&. 1 == 1 = 0x9908b0df
| otherwise = 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment