rounded-hw-0.2.0: test/FromRationalSpec.hs
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
module FromRationalSpec where
import Control.Monad
import Data.Proxy
import Data.Ratio
import Numeric.Rounded.Hardware.Internal
import Test.Hspec
import Test.Hspec.QuickCheck (prop)
import Test.QuickCheck
import Util
prop_fromRational_nearest_stock :: forall a. (RealFloat a, RoundedFractional a) => Proxy a -> Rational -> Property
prop_fromRational_nearest_stock _proxy x
= (roundedFromRational ToNearest x :: a)
`sameFloatP` (fromRational x :: a)
prop_roundedFromRational_check :: forall a. (RealFloat a, RoundedFractional a) => Proxy a -> RoundingMode -> Rational -> Property
prop_roundedFromRational_check _proxy r x
= (roundedFromRational_default r x :: a) -- the standard implementation
`sameFloatP` (roundedFromRational r x :: a) -- may be optimized
prop_fromRatio_order :: forall a. RealFloat a => Proxy a -> Rational -> Property
prop_fromRatio_order _proxy x
= let ne = roundedFromRational_default ToNearest x :: a
ze = roundedFromRational_default TowardZero x :: a
inf = roundedFromRational_default TowardInf x :: a
ninf = roundedFromRational_default TowardNegInf x :: a
in ninf <= inf
.&&. (ne == ninf || ne == inf)
.&&. (if x < 0 then ze == inf else ze == ninf)
prop_fromRatio_exact :: forall a. RealFloat a => Proxy a -> Rational -> Property
prop_fromRatio_exact _proxy x
= let inf = roundedFromRational_default TowardInf x :: a
ninf = roundedFromRational_default TowardNegInf x :: a
in if ninf == inf
then not (isInfinite inf) .&&. toRational inf === x
else if isInfinite inf
then inf > 0
.&&. not (isInfinite ninf)
.&&. toRational ninf =/= x
else if isInfinite ninf
then ninf < 0
.&&. not (isInfinite inf)
.&&. toRational inf =/= x
else toRational inf =/= x
.&&. toRational ninf =/= x
specT :: (RealFloat a, RoundedFractional a) => Proxy a -> Bool -> Spec
specT proxy checkAgainstStock = do
when checkAgainstStock $ do
-- Although fromRational for Double/Float correctly round to nearest, other types may not.
prop "fromRational (nearest) coincides with stock fromRational" $
forAllShrink variousRationals shrinkRealFrac $ prop_fromRational_nearest_stock proxy
prop "roundedFromRational coincides with the standard implementation" $ \r ->
forAllShrink variousRationals shrinkRealFrac $ prop_roundedFromRational_check proxy r
prop "order" $
forAllShrink variousRationals shrinkRealFrac $ prop_fromRatio_order proxy
prop "exactness" $
forAllShrink variousRationals shrinkRealFrac $ prop_fromRatio_exact proxy
spec :: Spec
spec = do
describe "Double" $ specT (Proxy :: Proxy Double) True
describe "Float" $ specT (Proxy :: Proxy Float) True