| 1 | module Main where |
|---|
| 2 | |
|---|
| 3 | import Control.Monad |
|---|
| 4 | import System.Random |
|---|
| 5 | |
|---|
| 6 | splitN :: (RandomGen g) => Int -> g -> ([g], g) |
|---|
| 7 | splitN 0 g = ([], g) |
|---|
| 8 | splitN n g = (g1:l, g') |
|---|
| 9 | where |
|---|
| 10 | (l, g') = splitN (n-1) g2 |
|---|
| 11 | (g1, g2) = split g |
|---|
| 12 | |
|---|
| 13 | -- The funny splitting operation. |
|---|
| 14 | split' :: (RandomGen g) => g -> (g, g) |
|---|
| 15 | split' g = (g12, g21) |
|---|
| 16 | where |
|---|
| 17 | (g1, g2) = split g |
|---|
| 18 | (_, g12) = split g1 |
|---|
| 19 | (g21, _) = split g2 |
|---|
| 20 | |
|---|
| 21 | -- This test checks if generators created by calling split 2 times are independent. |
|---|
| 22 | -- It generates pairs of integers from 0 to n-1, using split' to |
|---|
| 23 | -- generate both numbers using one seed. Then it counts how often the |
|---|
| 24 | -- two numbers are equal. |
|---|
| 25 | test :: (RandomGen g) => Int -> Int -> g -> Int |
|---|
| 26 | test numTests n g = equals |
|---|
| 27 | where |
|---|
| 28 | (gs, _) = splitN numTests g |
|---|
| 29 | equals = count id $ map single gs |
|---|
| 30 | count p l = length $ filter p l |
|---|
| 31 | single g' = (fst $ randomR (0, n-1) g1) == (fst $ randomR (0, n-1) g2) |
|---|
| 32 | where |
|---|
| 33 | (g1, g2) = split' g' |
|---|
| 34 | |
|---|
| 35 | main = do |
|---|
| 36 | g <- newStdGen |
|---|
| 37 | forM_ [2..15] $ \i -> do |
|---|
| 38 | let actual = test (i * 1000) i g |
|---|
| 39 | putStrLn $ "Generated " ++ show (i * 1000) |
|---|
| 40 | ++ " pairs of numbers from 0 to " ++ show (i - 1) |
|---|
| 41 | ++ " -- " ++ show actual ++ " pairs contained equal numbers " |
|---|
| 42 | ++ "and we expected about 1000." |
|---|