1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
|
module RangeTest (main) where
import Control.Monad
import System.Random
import Data.Int
import Data.Word
import Foreign.C.Types
-- Take many measurements and record the max/min/average random values.
approxBounds ::
(RandomGen g, Random a, Ord a, Num a) =>
(g -> (a,g)) -> Int -> a -> (a,a) -> g -> ((a,a,a),g)
-- Here we do a little hack to essentially pass in the type in the last argument:
approxBounds nxt iters unused (explo,exphi) initrng =
if False
then ((unused,unused,unused),undefined)
-- else loop initrng iters 100 (-100) 0 -- Oops, can't use minBound/maxBound here.
else loop initrng iters exphi explo 0
where
loop rng 0 mn mx sum' = ((mn,mx,sum'),rng)
loop rng n mn mx sum' =
case nxt rng of
(x, rng') -> loop rng' (n-1) (min x mn) (max x mx) (x+sum')
-- We check that:
-- (1) all generated numbers are in bounds
-- (2) we get "close" to the bounds
-- The with (2) is that we do enough trials to ensure that we can at
-- least hit the 90% mark.
checkBounds ::
(Real a, Show a, Ord a) =>
String -> (Bool, a, a) -> ((a,a) -> StdGen -> ((a, a, t), StdGen)) -> IO ()
checkBounds msg (exclusive,lo,hi) fun = do
-- (lo,hi) is [inclusive,exclusive)
putStr $ msg ++ ": "
(mn,mx,_) <- getStdRandom (fun (lo,hi))
when (mn < lo) $ error $ "broke lower bound: " ++ show mn
when (mx > hi) $ error $ "broke upper bound: " ++ show mx
when (exclusive && mx >= hi)$ error$ "hit upper bound: " ++ show mx
let epsilon = 0.1 * (toRational hi - toRational lo)
when (toRational (hi - mx) > epsilon) $ error $ "didn't get close enough to upper bound: "++ show mx
when (toRational (mn - lo) > epsilon) $ error $ "didn't get close enough to lower bound: "++ show mn
putStrLn "Passed"
boundedRange :: (Num a, Bounded a) => (Bool, a, a)
boundedRange = ( False, minBound, maxBound )
trials :: Int
trials = 5000
-- Keep in mind here that on some architectures (e.g. ARM) CChar, CWchar, and CSigAtomic
-- are unsigned
main :: IO ()
main =
do
checkBounds "Int" boundedRange (approxBounds random trials (undefined::Int))
checkBounds "Integer" (False, fromIntegral (minBound::Int), fromIntegral (maxBound::Int))
(approxBounds random trials (undefined::Integer))
checkBounds "Int8" boundedRange (approxBounds random trials (undefined::Int8))
checkBounds "Int16" boundedRange (approxBounds random trials (undefined::Int16))
checkBounds "Int32" boundedRange (approxBounds random trials (undefined::Int32))
checkBounds "Int64" boundedRange (approxBounds random trials (undefined::Int64))
checkBounds "Word" boundedRange (approxBounds random trials (undefined::Word))
checkBounds "Word8" boundedRange (approxBounds random trials (undefined::Word8))
checkBounds "Word16" boundedRange (approxBounds random trials (undefined::Word16))
checkBounds "Word32" boundedRange (approxBounds random trials (undefined::Word32))
checkBounds "Word64" boundedRange (approxBounds random trials (undefined::Word64))
checkBounds "Double" (False,0.0,1.0) (approxBounds random trials (undefined::Double))
checkBounds "Float" (False,0.0,1.0) (approxBounds random trials (undefined::Float))
checkBounds "CChar" boundedRange (approxBounds random trials (undefined:: CChar))
checkBounds "CSChar" boundedRange (approxBounds random trials (undefined:: CSChar))
checkBounds "CUChar" boundedRange (approxBounds random trials (undefined:: CUChar))
checkBounds "CShort" boundedRange (approxBounds random trials (undefined:: CShort))
checkBounds "CUShort" boundedRange (approxBounds random trials (undefined:: CUShort))
checkBounds "CInt" boundedRange (approxBounds random trials (undefined:: CInt))
checkBounds "CUInt" boundedRange (approxBounds random trials (undefined:: CUInt))
checkBounds "CLong" boundedRange (approxBounds random trials (undefined:: CLong))
checkBounds "CULong" boundedRange (approxBounds random trials (undefined:: CULong))
checkBounds "CPtrdiff" boundedRange (approxBounds random trials (undefined:: CPtrdiff))
checkBounds "CSize" boundedRange (approxBounds random trials (undefined:: CSize))
checkBounds "CWchar" boundedRange (approxBounds random trials (undefined:: CWchar))
checkBounds "CSigAtomic" boundedRange (approxBounds random trials (undefined:: CSigAtomic))
checkBounds "CLLong" boundedRange (approxBounds random trials (undefined:: CLLong))
checkBounds "CULLong" boundedRange (approxBounds random trials (undefined:: CULLong))
checkBounds "CIntPtr" boundedRange (approxBounds random trials (undefined:: CIntPtr))
checkBounds "CUIntPtr" boundedRange (approxBounds random trials (undefined:: CUIntPtr))
checkBounds "CIntMax" boundedRange (approxBounds random trials (undefined:: CIntMax))
checkBounds "CUIntMax" boundedRange (approxBounds random trials (undefined:: CUIntMax))
-- Then check all the range-restricted versions:
checkBounds "Int R" (False,-100,100) (approxBounds (randomR (-100,100)) trials (undefined::Int))
checkBounds "Integer R"
(False,-100000000000000000000,100000000000000000000)
(approxBounds (randomR (-100000000000000000000,100000000000000000000)) trials (undefined::Integer))
checkBounds "Int8 R" (False,-100,100) (approxBounds (randomR (-100,100)) trials (undefined::Int8))
checkBounds "Int8 Rsmall" (False,-50,50) (approxBounds (randomR (-50,50)) trials (undefined::Int8))
checkBounds "Int8 Rmini" (False,3,4) (approxBounds (randomR (3,4)) trials (undefined::Int8))
checkBounds "Int8 Rtrivial" (False,3,3) (approxBounds (randomR (3,3)) trials (undefined::Int8))
checkBounds "Int16 R" (False,-100,100) (approxBounds (randomR (-100,100)) trials (undefined::Int16))
checkBounds "Int32 R" (False,-100,100) (approxBounds (randomR (-100,100)) trials (undefined::Int32))
checkBounds "Int64 R" (False,-100,100) (approxBounds (randomR (-100,100)) trials (undefined::Int64))
checkBounds "Word R" (False,0,200) (approxBounds (randomR (0,200)) trials (undefined::Word))
checkBounds "Word8 R" (False,0,200) (approxBounds (randomR (0,200)) trials (undefined::Word8))
checkBounds "Word16 R" (False,0,200) (approxBounds (randomR (0,200)) trials (undefined::Word16))
checkBounds "Word32 R" (False,0,200) (approxBounds (randomR (0,200)) trials (undefined::Word32))
checkBounds "Word64 R" (False,0,200) (approxBounds (randomR (0,200)) trials (undefined::Word64))
checkBounds "Double R" (False,10.0,77.0) (approxBounds (randomR (10,77)) trials (undefined::Double))
checkBounds "Float R" (False,10.0,77.0) (approxBounds (randomR (10,77)) trials (undefined::Float))
checkBounds "CChar R" (False,0,100) (approxBounds (randomR (0,100)) trials (undefined:: CChar))
checkBounds "CSChar R" (False,-100,100) (approxBounds (randomR (-100,100)) trials (undefined:: CSChar))
checkBounds "CUChar R" (False,0,200) (approxBounds (randomR (0,200)) trials (undefined:: CUChar))
checkBounds "CShort R" (False,-100,100) (approxBounds (randomR (-100,100)) trials (undefined:: CShort))
checkBounds "CUShort R" (False,0,200) (approxBounds (randomR (0,200)) trials (undefined:: CUShort))
checkBounds "CInt R" (False,-100,100) (approxBounds (randomR (-100,100)) trials (undefined:: CInt))
checkBounds "CUInt R" (False,0,200) (approxBounds (randomR (0,200)) trials (undefined:: CUInt))
checkBounds "CLong R" (False,-100,100) (approxBounds (randomR (-100,100)) trials (undefined:: CLong))
checkBounds "CULong R" (False,0,200) (approxBounds (randomR (0,200)) trials (undefined:: CULong))
checkBounds "CPtrdiff R" (False,-100,100) (approxBounds (randomR (-100,100)) trials (undefined:: CPtrdiff))
checkBounds "CSize R" (False,0,200) (approxBounds (randomR (0,200)) trials (undefined:: CSize))
checkBounds "CWchar R" (False,0,100) (approxBounds (randomR (0,100)) trials (undefined:: CWchar))
checkBounds "CSigAtomic R" (False,0,100) (approxBounds (randomR (0,100)) trials (undefined:: CSigAtomic))
checkBounds "CLLong R" (False,-100,100) (approxBounds (randomR (-100,100)) trials (undefined:: CLLong))
checkBounds "CULLong R" (False,0,200) (approxBounds (randomR (0,200)) trials (undefined:: CULLong))
checkBounds "CIntPtr R" (False,-100,100) (approxBounds (randomR (-100,100)) trials (undefined:: CIntPtr))
checkBounds "CUIntPtr R" (False,0,200) (approxBounds (randomR (0,200)) trials (undefined:: CUIntPtr))
checkBounds "CIntMax R" (False,-100,100) (approxBounds (randomR (-100,100)) trials (undefined:: CIntMax))
checkBounds "CUIntMax R" (False,0,200) (approxBounds (randomR (0,200)) trials (undefined:: CUIntMax))
-- Untested:
-- instance Random Char where
-- instance Random Bool where
-- instance Random Integer where
|