{-# LANGUAGE DataKinds #-} {-# LANGUAGE ScopedTypeVariables #-} module ShowFloatSpec where import Data.Int import Data.Proxy import Numeric import Numeric.Rounded.Hardware.Internal import Test.Hspec import Test.Hspec.QuickCheck (prop) import Test.QuickCheck import Util () prop_showEFloat_nearest :: forall a. RealFloat a => Proxy a -> Int -> Int32 -> Property prop_showEFloat_nearest _proxy prec x = showEFloat mprec x' "" === showEFloatRn ToNearest mprec x' "" where mprec = Just prec x' = fromIntegral x / 64 :: a prop_showFFloat_nearest :: forall a. RealFloat a => Proxy a -> Int -> Int32 -> Property prop_showFFloat_nearest _proxy prec x = showFFloat mprec x' "" === showFFloatRn ToNearest mprec x' "" where mprec = Just prec x' = fromIntegral x / 64 :: a prop_showGFloat_nearest :: forall a. RealFloat a => Proxy a -> Int -> Int32 -> Property prop_showGFloat_nearest _proxy prec x = showGFloat mprec x' "" === showGFloatRn ToNearest mprec x' "" where mprec = Just prec x' = fromIntegral x / 64 :: a prop_showEFloat :: forall a. RealFloat a => Proxy a -> Maybe Int -> a -> Property prop_showEFloat _proxy mprec x = let rn = showEFloatRn ToNearest mprec x "" ru = showEFloatRn TowardInf mprec x "" rd = showEFloatRn TowardNegInf mprec x "" rz = showEFloatRn TowardZero mprec x "" in rn === ru .||. rn === rd .||. rz === (if x > 0 then rd else ru) prop_showFFloat :: forall a. RealFloat a => Proxy a -> Maybe Int -> a -> Property prop_showFFloat _proxy mprec x = let rn = showFFloatRn ToNearest mprec x "" ru = showFFloatRn TowardInf mprec x "" rd = showFFloatRn TowardNegInf mprec x "" rz = showFFloatRn TowardZero mprec x "" in rn === ru .||. rn === rd .||. rz === (if x > 0 then rd else ru) prop_showGFloat :: forall a. RealFloat a => Proxy a -> Maybe Int -> a -> Property prop_showGFloat _proxy mprec x = let rn = showGFloatRn ToNearest mprec x "" ru = showGFloatRn TowardInf mprec x "" rd = showGFloatRn TowardNegInf mprec x "" rz = showGFloatRn TowardZero mprec x "" in rn === ru .||. rn === rd .||. rz === (if x > 0 then rd else ru) testAgainstNumeric :: forall a. RealFloat a => Proxy a -> Spec testAgainstNumeric proxy = do describe "showFloat" $ do prop "showEFloat (nearest)" $ prop_showEFloat_nearest proxy prop "showFFloat (nearest)" $ prop_showFFloat_nearest proxy prop "showGFloat (nearest)" $ prop_showGFloat_nearest proxy prop "showEFloat/Int32" $ \mprec (x :: Int32) -> showEFloat mprec (fromIntegral x :: a) "" === showEFloatRn ToNearest mprec (fromIntegral x :: a) "" prop "showFFloat/Int32" $ \mprec (x :: Int32) -> showFFloat mprec (fromIntegral x :: a) "" === showFFloatRn ToNearest mprec (fromIntegral x :: a) "" prop "showGFloat/Int32" $ \mprec (x :: Int32) -> showGFloat mprec (fromIntegral x :: a) "" === showGFloatRn ToNearest mprec (fromIntegral x :: a) "" specT :: forall a. (RealFloat a, Arbitrary a, Show a) => Proxy a -> Spec specT proxy = do prop "showEFloat" $ prop_showEFloat proxy prop "showFFloat" $ prop_showFFloat proxy prop "showGFloat" $ prop_showGFloat proxy -- 0.5 should be exactly representable in the type... do let x = 0.5 `asProxyTypeOf` proxy prop "showFFloatRn Nothing 0.5" $ \r -> showFFloatRn r Nothing x "" === "0.5" prop "showFFloatRn (Just 0) 0.5" $ \r -> showFFloatRn r (Just 0) x "" === (if r == TowardInf then "1" else "0") prop "showFFloatRn (Just 3) 0.5" $ \r -> showFFloatRn r (Just 3) x "" === "0.500" prop "showGFloatRn Nothing 0.5" $ \r -> showGFloatRn r Nothing x "" === "0.5" prop "showGFloatRn (Just 0) 0.5" $ \r -> showGFloatRn r (Just 0) x "" === (if r == TowardInf then "1" else "0") prop "showGFloatRn (Just 3) 0.5" $ \r -> showGFloatRn r (Just 3) x "" === "0.500" prop "showEFloatRn Nothing 0.5" $ \r -> showEFloatRn r Nothing x "" === "5.0e-1" prop "showEFloatRn (Just 0) 0.5" $ \r -> showEFloatRn r (Just 0) x "" === "5e-1" prop "showEFloatRn (Just 3) 0.5" $ \r -> showEFloatRn r (Just 3) x "" === "5.000e-1" -- -17.5625 should be exactly representable in the type... do let x = (-17.5625) `asProxyTypeOf` proxy prop "showFFloatRn Nothing -17.5625" $ \r -> showFFloatRn r Nothing x "" === "-17.5625" prop "showFFloatRn (Just 0) -17.5625" $ \r -> showFFloatRn r (Just 0) x "" === (if r == TowardInf || r == TowardZero then "-17" else "-18") prop "showFFloatRn (Just 3) -17.5625" $ \r -> showFFloatRn r (Just 3) x "" === (if r == TowardNegInf then "-17.563" else "-17.562") prop "showFFloatRn (Just 6) -17.5625" $ \r -> showFFloatRn r (Just 6) x "" === "-17.562500" prop "showGFloatRn Nothing -17.5625" $ \r -> showGFloatRn r Nothing x "" === "-17.5625" prop "showGFloatRn (Just 0) -17.5625" $ \r -> showGFloatRn r (Just 0) x "" === (if r == TowardInf || r == TowardZero then "-17" else "-18") prop "showGFloatRn (Just 3) -17.5625" $ \r -> showGFloatRn r (Just 3) x "" === (if r == TowardNegInf then "-17.563" else "-17.562") prop "showGFloatRn (Just 6) -17.5625" $ \r -> showGFloatRn r (Just 6) x "" === "-17.562500" prop "showEFloatRn Nothing -17.5625" $ \r -> showEFloatRn r Nothing x "" === "-1.75625e1" prop "showEFloatRn (Just 0) -17.5625" $ \r -> showEFloatRn r (Just 0) x "" === (if r == TowardInf || r == TowardZero then "-1e1" else "-2e1") prop "showEFloatRn (Just 3) -17.5625" $ \r -> showEFloatRn r (Just 3) x "" === (if r == TowardNegInf then "-1.757e1" else "-1.756e1") prop "showEFloatRn (Just 6) -17.5625" $ \r -> showEFloatRn r (Just 6) x "" === "-1.756250e1" spec :: Spec spec = do describe "Double" $ testAgainstNumeric (Proxy :: Proxy Double) -- The functions in Numeric yields a rounded value: -- >>> showFFloat Nothing (137846.59375 :: Float) "" -- "137846.6" -- So comparing them -- describe "Float" $ testAgainstNumeric (Proxy :: Proxy Float) describe "Double" $ specT (Proxy :: Proxy Double) describe "Float" $ specT (Proxy :: Proxy Float)