fp-ieee-0.1.0: test/ClassificationSpec.hs
module ClassificationSpec where
import Data.Function (on)
import Data.Functor.Identity
import Data.Proxy
import Numeric.Floating.IEEE
import Test.Hspec
import Test.Hspec.QuickCheck
import Test.QuickCheck hiding (classify)
import Util
default ()
prop_classify :: (RealFloat a, Show a) => Proxy a -> a -> Property
prop_classify _ x = conjoin
[ counterexample "NegativeInfinity" $ (c == NegativeInfinity) === (x < 0 && isInfinite x)
, counterexample "NegativeNormal" $ (c == NegativeNormal) === (x < 0 && isNormal x)
, counterexample "NegativeSubnormal" $ (c == NegativeSubnormal) === (x < 0 && isDenormalized x)
, counterexample "NegativeZero" $ (c == NegativeZero) === (isNegativeZero x)
, counterexample "PositiveZero" $ (c == PositiveZero) === (x == 0 && not (isNegativeZero x))
, counterexample "PositiveSubnormal" $ (c == PositiveSubnormal) === (x > 0 && isDenormalized x)
, counterexample "PositiveNormal" $ (c == PositiveNormal) === (x > 0 && isNormal x)
, counterexample "PositiveInfinity" $ (c == PositiveInfinity) === (x > 0 && isInfinite x)
, counterexample "isNaN" $ isNaN x === (c == SignalingNaN || c == QuietNaN)
, counterexample "isInfinite" $ isInfinite x === (c == NegativeInfinity || c == PositiveInfinity)
, counterexample "isNormal" $ isNormal x === (c == NegativeNormal || c == PositiveNormal)
, counterexample "isDenormalized" $ isDenormalized x === (c == NegativeSubnormal || c == PositiveSubnormal)
, counterexample "isZero" $ isZero x === (c == NegativeZero || c == PositiveZero)
, counterexample "isFinite" $ isFinite x === (c `elem` [NegativeNormal, NegativeSubnormal, NegativeZero, PositiveZero, PositiveSubnormal, PositiveNormal])
, counterexample "isSignMinus" $ isSignMinus x === (c `elem` [NegativeInfinity, NegativeNormal, NegativeSubnormal, NegativeZero]) -- isSignMinus doesn't handle negative NaNs
]
where c = classify x
{-# SPECIALIZE prop_classify :: Proxy Float -> Float -> Property, Proxy Double -> Double -> Property #-}
prop_totalOrder :: RealFloat a => Proxy a -> a -> a -> Property
prop_totalOrder proxy x y = let cmp_x_y = compareByTotalOrder x y
cmp_y_x = compareByTotalOrder y x
in cmp_x_y === compare EQ cmp_y_x
.&&. (if x < y then cmp_x_y === LT else property True)
.&&. (if y < x then cmp_x_y === GT else property True)
{-# SPECIALIZE prop_totalOrder :: Proxy Float -> Float -> Float -> Property, Proxy Double -> Double -> Double -> Property #-}
spec :: Spec
spec = do
describe "Double" $ do
let proxy :: Proxy Double
proxy = Proxy
prop "classify" $ forAllFloats $ prop_classify proxy
prop "totalOrder" $ forAllFloats2 $ prop_totalOrder proxy
describe "Double (generic)" $ do
let proxy :: Proxy (Identity Double)
proxy = Proxy
prop "classify" $ forAllFloats $ prop_classify proxy . Identity
prop "totalOrder" $ forAllFloats2 (prop_totalOrder proxy `on` Identity)
describe "Float" $ do
let proxy :: Proxy Float
proxy = Proxy
prop "classify" $ forAllFloats $ prop_classify proxy
prop "totalOrder" $ forAllFloats2 $ prop_totalOrder proxy
describe "Float (generic)" $ do
let proxy :: Proxy (Identity Float)
proxy = Proxy
prop "classify" $ forAllFloats $ prop_classify proxy . Identity
prop "totalOrder" $ forAllFloats2 (prop_totalOrder proxy `on` Identity)