----------------------------------------------------------------------------- -- | -- Module : Numeric.Random.Generator.MT19937 -- Copyright : (c) Matt Harden 1999 -- License : GPL -- -- Maintainer : m.p.donadio@ieee.org -- Stability : experimental -- Portability : portable -- -- A Haskell program for MT19937 pseudorandom number generator -- ----------------------------------------------------------------------------- -- The original source was found at -- -- http://members.primary.net/~matth/mt19937.hs -- -- but I can't get to the site anymore. As much as the orginal -- formatting has been retained as possible. --mpd -- TODO: Make an instance of RandomGen class {- Function genrand generates an infinite list of pseudorandom unsigned integers (32bit) which are uniformly distributed among 0 to 2^32-1. sgenrand(seed) uses an algorithm of Knuth to provide 624 initial values to genrand(). Rewritten in Haskell by Matt Harden from original code in C by Takuji Nishimura. This program relies upon the GHC/Hugs extensions to Haskell. These are very likely to be available in any Haskell environment, and performance would suffer greatly without them. -} {- This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -} -- Copyright (C) 1999 Matt Harden -- The original C code contained the following notice: -- When you use this, send an email to: matumoto@math.keio.ac.jp -- with an appropriate reference to your work. {- REFERENCE - M. Matsumoto and T. Nishimura, "Mersenne Twister: A 623-Dimensionally Equidistributed Uniform Pseudo-Random Number Generator", ACM Transactions on Modeling and Computer Simulation, Vol. 8, No. 1, January 1998, pp 3--30. -} module Numeric.Random.Generator.MT19937 (W, genrand, test) where import Data.Word import Data.Bits infixl 8 .<<., .>>. (.<<.), (.>>.) :: (Bits a) => (a -> Int -> a) (.<<.) = shiftL (.>>.) = shiftR type W = Word32 -- Period parameters parmN :: Int parmN = 624 parmM :: Int parmM = 397 parmA :: W parmA = 0x9908b0df upperMask :: W upperMask = (bit 31) lowerMask :: W lowerMask = (complement upperMask) -- Tempering parameters temperingMaskB :: W -> W temperingMaskB = (.&. 0x9d2c5680) temperingMaskC :: W -> W temperingMaskC = (.&. 0xefc60000) temperingShiftU :: W -> W temperingShiftU = (.>>. 11) temperingShiftS :: W -> W temperingShiftS = (.<<. 7) temperingShiftT :: W -> W temperingShiftT = (.<<. 15) temperingShiftL :: W -> W temperingShiftL = (.>>. 18) -- A Knuth algorithm just to seed the seed... -- Line 25 of table 1 -- in [KNUTH 1981, The Art of Computer Programming Vol. 2 (2nd Ed.), pp102] sgenrand :: W -> [W] sgenrand 0 = sgenrand 4357 -- 0 not acceptable. Why 4357? I dunno. sgenrand seed = take parmN (iterate (69069 *) seed) mag01 :: Bool -> W mag01 False = 0 mag01 True = parmA tempering :: W -> W tempering = let (^=) x f = xor x (f x) in (^= (temperingShiftL)) . (^= (temperingMaskC . temperingShiftT)) . (^= (temperingMaskB . temperingShiftS)) . (^= (temperingShiftU)) -- parameter to rand MUST be a list of (_N) words! rand :: [W] -> [W] rand seed = map tempering r2 where r = seed ++ r2 r2 = zipWith xor (map f r3) (drop parmM r) r3 = zipWith (\x y -> (x .&. upperMask) .|. (y .&. lowerMask)) r (tail r) f y = (y .>>. 1) `xor` (mag01 (odd y)) genrand :: W -> [W] genrand = rand . sgenrand test :: IO () test = sequence_ $ map print $ take 1000 $ genrand 4357