import Control.Monad import Data.Bits import Data.List (sortBy) import Data.Ord -- | test-values to use as numerator/denominator posvals :: [Integer] posvals = [1,2,3,4,5,9,10,14,15,16,17] ++ [ n | e <- ([5..70]++[96,128,160,192,224]) , ofs <- [-1..1], let n = bit e + ofs ] posvalsSum :: Integer posvalsSum = 0x300000003000000030000000300000003000001800000000000000000 vals :: [Integer] vals = sortBy (comparing abs) $ map negate posvals ++ [0] ++ posvals main :: IO () main = do unless (sum posvals == posvalsSum) $ fail $ "sum posvals == " ++ show (sum posvals) forM_ [ (n,d) | n <- vals, d <- vals, d /= 0 ] $ \(n,d) -> do let check sp p = unless (p n d) $ fail (sp ++ " " ++ show n ++ " " ++ show d) check "rem0" prop_rem0 check "mod0" prop_mod0 check "divMod0" prop_divMod0 check "divMod1" prop_divMod1 check "divMod2" prop_divMod2 check "quotRem0" prop_quotRem0 check "quotRem1" prop_quotRem1 check "quotRem2" prop_quotRem2 -- putStrLn "passed" -- QuickCheck style properties prop_rem0 :: Integer -> Integer -> Bool prop_rem0 n d | n >= 0 = (n `rem` d) `inside` (-1,abs d) | otherwise = (n `rem` d) `inside` (-(abs d),1) where inside v (l,u) = l < v && v < u prop_mod0 :: Integer -> Integer -> Bool prop_mod0 n d | d >= 0 = (n `mod` d) `inside` (-1,d) | otherwise = (n `mod` d) `inside` (d,1) where inside v (l,u) = l < v && v < u -- | Invariant from Haskell Report prop_divMod0 :: Integer -> Integer -> Bool prop_divMod0 n d = (n `div` d) * d + (n `mod` d) == n prop_divMod1 :: Integer -> Integer -> Bool prop_divMod1 n d = divMod n d == (n `div` d, n `mod` d) -- | Compare IUT to implementation of 'divMod' in terms of 'quotRem' prop_divMod2 :: Integer -> Integer -> Bool prop_divMod2 n d = divMod n d == divMod' n d where divMod' x y = if signum r == negate (signum y) then (q-1, r+y) else qr where qr@(q,r) = quotRem x y -- | Invariant from Haskell Report prop_quotRem0 :: Integer -> Integer -> Bool prop_quotRem0 n d = (n `quot` d) * d + (n `rem` d) == n prop_quotRem1 :: Integer -> Integer -> Bool prop_quotRem1 n d = quotRem n d == (n `quot` d, n `rem` d) -- | Test symmetry properties of 'quotRem' prop_quotRem2 :: Integer -> Integer -> Bool prop_quotRem2 n d = (qr == negQ (quotRem n (-d)) && qr == negR (quotRem (-n) (-d)) && qr == (negQ . negR) (quotRem (-n) d)) where qr = quotRem n d negQ (q,r) = (-q,r) negR (q,r) = (q,-r)