packages feed

safe-decimal 0.2.0.0 → 0.2.1.0

raw patch · 8 files changed

+243/−80 lines, 8 filesdep −template-haskelldep ~doctestsetup-changedPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies removed: template-haskell

Dependency ranges changed: doctest

API changes (from Hackage documentation)

+ Numeric.Decimal: data RoundHalfFromZero
+ Numeric.Decimal: data RoundHalfToZero
+ Numeric.Decimal: instance Numeric.Decimal.Internal.Round Numeric.Decimal.RoundHalfFromZero GHC.Int.Int16
+ Numeric.Decimal: instance Numeric.Decimal.Internal.Round Numeric.Decimal.RoundHalfFromZero GHC.Int.Int32
+ Numeric.Decimal: instance Numeric.Decimal.Internal.Round Numeric.Decimal.RoundHalfFromZero GHC.Int.Int64
+ Numeric.Decimal: instance Numeric.Decimal.Internal.Round Numeric.Decimal.RoundHalfFromZero GHC.Int.Int8
+ Numeric.Decimal: instance Numeric.Decimal.Internal.Round Numeric.Decimal.RoundHalfFromZero GHC.Integer.Type.Integer
+ Numeric.Decimal: instance Numeric.Decimal.Internal.Round Numeric.Decimal.RoundHalfFromZero GHC.Types.Int
+ Numeric.Decimal: instance Numeric.Decimal.Internal.Round Numeric.Decimal.RoundHalfFromZero GHC.Types.Word
+ Numeric.Decimal: instance Numeric.Decimal.Internal.Round Numeric.Decimal.RoundHalfFromZero GHC.Word.Word16
+ Numeric.Decimal: instance Numeric.Decimal.Internal.Round Numeric.Decimal.RoundHalfFromZero GHC.Word.Word32
+ Numeric.Decimal: instance Numeric.Decimal.Internal.Round Numeric.Decimal.RoundHalfFromZero GHC.Word.Word64
+ Numeric.Decimal: instance Numeric.Decimal.Internal.Round Numeric.Decimal.RoundHalfFromZero GHC.Word.Word8
+ Numeric.Decimal: instance Numeric.Decimal.Internal.Round Numeric.Decimal.RoundHalfToZero GHC.Int.Int16
+ Numeric.Decimal: instance Numeric.Decimal.Internal.Round Numeric.Decimal.RoundHalfToZero GHC.Int.Int32
+ Numeric.Decimal: instance Numeric.Decimal.Internal.Round Numeric.Decimal.RoundHalfToZero GHC.Int.Int64
+ Numeric.Decimal: instance Numeric.Decimal.Internal.Round Numeric.Decimal.RoundHalfToZero GHC.Int.Int8
+ Numeric.Decimal: instance Numeric.Decimal.Internal.Round Numeric.Decimal.RoundHalfToZero GHC.Integer.Type.Integer
+ Numeric.Decimal: instance Numeric.Decimal.Internal.Round Numeric.Decimal.RoundHalfToZero GHC.Types.Int
+ Numeric.Decimal: instance Numeric.Decimal.Internal.Round Numeric.Decimal.RoundHalfToZero GHC.Types.Word
+ Numeric.Decimal: instance Numeric.Decimal.Internal.Round Numeric.Decimal.RoundHalfToZero GHC.Word.Word16
+ Numeric.Decimal: instance Numeric.Decimal.Internal.Round Numeric.Decimal.RoundHalfToZero GHC.Word.Word32
+ Numeric.Decimal: instance Numeric.Decimal.Internal.Round Numeric.Decimal.RoundHalfToZero GHC.Word.Word64
+ Numeric.Decimal: instance Numeric.Decimal.Internal.Round Numeric.Decimal.RoundHalfToZero GHC.Word.Word8
+ Numeric.Decimal: roundHalfFromZero :: forall r n k p. (Integral p, KnownNat k) => Decimal r (n + k) p -> Decimal r n p
+ Numeric.Decimal: roundHalfToZero :: forall r n k p. (Integral p, KnownNat k) => Decimal r (n + k) p -> Decimal r n p
+ Numeric.Decimal.BoundedArithmetic: arithError :: HasCallStack => Arith a -> a
+ Numeric.Decimal.BoundedArithmetic: instance GHC.Enum.Bounded a => GHC.Enum.Bounded (Numeric.Decimal.BoundedArithmetic.Arith a)
- Numeric.Decimal: Decimal :: p -> Decimal r p
+ Numeric.Decimal: Decimal :: p -> Decimal r (s :: Nat) p

Files

ChangeLog.md view
@@ -1,5 +1,12 @@ # Changelog for safe-decimal +## 0.2.1++* Add `arithError`+* Add `RoundHalfToZero` and `RoundHalfFromZero` rounding strategies.+* Conversion from `Scientific` normalizes the input and is more resilient to unbounded+  computation for bounded `Decimal` result.+ ## 0.2.0  * Add `Arith` monad and corresponding functions.
Setup.hs view
@@ -1,34 +1,4 @@-{-# LANGUAGE CPP #-}-{-# OPTIONS_GHC -Wall #-}-module Main (main) where--#ifndef MIN_VERSION_cabal_doctest-#define MIN_VERSION_cabal_doctest(x,y,z) 0-#endif--#if MIN_VERSION_cabal_doctest(1,0,0)--import Distribution.Extra.Doctest ( defaultMainWithDoctests )-main :: IO ()-main = defaultMainWithDoctests "doctests"--#else--#ifdef MIN_VERSION_Cabal--- If the macro is defined, we have new cabal-install,--- but for some reason we don't have cabal-doctest in package-db------ Probably we are running cabal sdist, when otherwise using new-build--- workflow-#warning You are configuring this package without cabal-doctest installed. \-         The doctests test-suite will not work as a result. \-         To fix this, install cabal-doctest before configuring.-#endif- import Distribution.Simple  main :: IO () main = defaultMain--#endif-
safe-decimal.cabal view
@@ -1,16 +1,16 @@ name:           safe-decimal-version:        0.2.0.0+version:        0.2.1.0 description:    Please see the README on GitHub at <https://github.com/fpco/safe-decimal#readme> synopsis:       Safe and very efficient arithmetic operations on fixed decimal point numbers category:       Math, Numeric, Numerical homepage:       https://github.com/fpco/safe-decimal#readme bug-reports:    https://github.com/fpco/safe-decimal/issues author:         Alexey Kuleshevich-maintainer:     alexey@fpcomplete.com-copyright:      2018-2019 FP Complete+maintainer:     alexey@kuleshevi.ch+copyright:      2018-2020 FP Complete, 2021 Alexey Kuleshevich license:        BSD3 license-file:   LICENSE-build-type:     Custom+build-type:     Simple cabal-version:  >= 1.10 extra-source-files: ChangeLog.md                     README.md@@ -19,11 +19,6 @@   type: git   location: https://github.com/fpco/safe-decimal -custom-setup-  setup-depends:-      base-    , Cabal-    , cabal-doctest >=1.0.6  library   exposed-modules: Numeric.Decimal@@ -42,10 +37,8 @@   hs-source-dirs:   tests   main-is:          doctests.hs   build-depends: base-               , doctest >=0.15-               , QuickCheck+               , doctest >=0.16                , safe-decimal-               , template-haskell   default-language:    Haskell2010   ghc-options:        -Wall                       -Wincomplete-record-updates
src/Numeric/Decimal.hs view
@@ -1,5 +1,5 @@-{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE InstanceSigs #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE ScopedTypeVariables #-}@@ -12,7 +12,7 @@     module Numeric.Decimal.BoundedArithmetic   , module Numeric.Decimal.Internal   -- * Rounding-    -- ** Round half up+  -- ** Round half up   , RoundHalfUp   , roundHalfUp   -- ** Round half down@@ -21,6 +21,12 @@   -- ** Round half even   , RoundHalfEven   , roundHalfEven+  -- ** Round half to zero+  , RoundHalfToZero+  , roundHalfToZero+  -- ** Round half from zero+  , RoundHalfFromZero+  , roundHalfFromZero   -- ** Round down   , RoundDown   , Floor@@ -51,9 +57,9 @@ import Data.Coerce import Data.Fixed import Data.Int-import Data.Word import Data.Proxy import Data.Scientific+import Data.Word import GHC.TypeLits import Numeric.Decimal.BoundedArithmetic import Numeric.Decimal.Internal@@ -294,6 +300,144 @@       (q, r) = (2 *) <$> quotRem x s1 {-# INLINABLE roundHalfEven #-} +-- | [Round half towards zero](https://en.wikipedia.org/wiki/Rounding#Round_half_towards_zero) rounding+-- strategy. If the fraction of x is exactly 0.5, then y = x − 0.5 if x is positive, and y = x + 0.5 if x is negative.+--+-- >>> :set -XDataKinds+-- >>> :set -XTypeApplications+-- >>> arithRoundD @1 @RoundHalfToZero @3 @Int 3.650+-- Arith 3.6+-- >>> arithRoundD @1 @RoundHalfToZero @3 @Int 3.740+-- Arith 3.7+-- >>> arithRoundD @1 @RoundHalfToZero @4 @Int 3.7501+-- Arith 3.8+-- >>> arithRoundD @1 @RoundHalfToZero @3 @Int (-3.650)+-- Arith -3.6+-- >>> arithRoundD @1 @RoundHalfToZero @3 @Int (-3.740)+-- Arith -3.7+-- >>> arithRoundD @1 @RoundHalfToZero @4 @Int (-3.7501)+-- Arith -3.8+-- >>> arithRoundD @1 @RoundHalfToZero @3 @Int (-3.760)+-- Arith -3.8++-- @since 0.2.0+data RoundHalfToZero++instance Round RoundHalfToZero Integer where+  roundDecimal = roundHalfToZero+  {-# INLINABLE roundDecimal #-}+instance Round RoundHalfToZero Int where+  roundDecimal = roundHalfToZero+  {-# INLINABLE roundDecimal #-}+instance Round RoundHalfToZero Int8 where+  roundDecimal = roundHalfToZero+  {-# INLINABLE roundDecimal #-}+instance Round RoundHalfToZero Int16 where+  roundDecimal = roundHalfToZero+  {-# INLINABLE roundDecimal #-}+instance Round RoundHalfToZero Int32 where+  roundDecimal = roundHalfToZero+  {-# INLINABLE roundDecimal #-}+instance Round RoundHalfToZero Int64 where+  roundDecimal = roundHalfToZero+  {-# INLINABLE roundDecimal #-}+instance Round RoundHalfToZero Word where+  roundDecimal = roundHalfToZero+  {-# INLINABLE roundDecimal #-}+instance Round RoundHalfToZero Word8 where+  roundDecimal = roundHalfToZero+  {-# INLINABLE roundDecimal #-}+instance Round RoundHalfToZero Word16 where+  roundDecimal = roundHalfToZero+  {-# INLINABLE roundDecimal #-}+instance Round RoundHalfToZero Word32 where+  roundDecimal = roundHalfToZero+  {-# INLINABLE roundDecimal #-}+instance Round RoundHalfToZero Word64 where+  roundDecimal = roundHalfToZero+  {-# INLINABLE roundDecimal #-}++roundHalfToZero :: forall r n k p . (Integral p, KnownNat k) => Decimal r (n + k) p -> Decimal r n p+roundHalfToZero (Decimal x)+    | k == 0                     = Decimal x+    | r > s1                     = Decimal (q + 1)+    | signum r < 0 && abs r > s1 = Decimal (q - 1)+    | otherwise                  = Decimal q+    where+      k = fromIntegral (natVal (Proxy :: Proxy k)) :: Int+      s1 = 10 ^ k+      (q, r) = (2 *) <$> quotRem x s1+{-# INLINABLE roundHalfToZero #-}++-- | [Round half away from zero](https://en.wikipedia.org/wiki/Rounding#Round_half_away_from_zero) rounding+-- strategy. If the fraction of x is exactly 0.5, then y = x + 0.5 if x is positive, and y = x − 0.5 if x is negative.+--+-- >>> :set -XDataKinds+-- >>> :set -XTypeApplications+-- >>> arithRoundD @1 @RoundHalfFromZero @3 @Int 3.650+-- Arith 3.7+-- >>> arithRoundD @1 @RoundHalfFromZero @3 @Int 3.740+-- Arith 3.7+-- >>> arithRoundD @1 @RoundHalfFromZero @3 @Int 3.751+-- Arith 3.8+-- >>> arithRoundD @1 @RoundHalfFromZero @3 @Int (-3.650)+-- Arith -3.7+-- >>> arithRoundD @1 @RoundHalfFromZero @3 @Int (-3.740)+-- Arith -3.7+-- >>> arithRoundD @1 @RoundHalfFromZero @3 @Int (-3.751)+-- Arith -3.8+-- >>> arithRoundD @1 @RoundHalfFromZero @3 @Int (-3.760)+-- Arith -3.8++-- @since 0.2.0+data RoundHalfFromZero++instance Round RoundHalfFromZero Integer where+  roundDecimal = roundHalfFromZero+  {-# INLINABLE roundDecimal #-}+instance Round RoundHalfFromZero Int where+  roundDecimal = roundHalfFromZero+  {-# INLINABLE roundDecimal #-}+instance Round RoundHalfFromZero Int8 where+  roundDecimal = roundHalfFromZero+  {-# INLINABLE roundDecimal #-}+instance Round RoundHalfFromZero Int16 where+  roundDecimal = roundHalfFromZero+  {-# INLINABLE roundDecimal #-}+instance Round RoundHalfFromZero Int32 where+  roundDecimal = roundHalfFromZero+  {-# INLINABLE roundDecimal #-}+instance Round RoundHalfFromZero Int64 where+  roundDecimal = roundHalfFromZero+  {-# INLINABLE roundDecimal #-}+instance Round RoundHalfFromZero Word where+  roundDecimal = roundHalfFromZero+  {-# INLINABLE roundDecimal #-}+instance Round RoundHalfFromZero Word8 where+  roundDecimal = roundHalfFromZero+  {-# INLINABLE roundDecimal #-}+instance Round RoundHalfFromZero Word16 where+  roundDecimal = roundHalfFromZero+  {-# INLINABLE roundDecimal #-}+instance Round RoundHalfFromZero Word32 where+  roundDecimal = roundHalfFromZero+  {-# INLINABLE roundDecimal #-}+instance Round RoundHalfFromZero Word64 where+  roundDecimal = roundHalfFromZero+  {-# INLINABLE roundDecimal #-}++roundHalfFromZero :: forall r n k p . (Integral p, KnownNat k) => Decimal r (n + k) p -> Decimal r n p+roundHalfFromZero (Decimal x)+    | k == 0                      = Decimal x+    | r >= s1                     = Decimal (q + 1)+    | signum r < 0 && abs r >= s1 = Decimal (q - 1)+    | otherwise                   = Decimal q+    where+      k = fromIntegral (natVal (Proxy :: Proxy k)) :: Int+      s1 = 10 ^ k+      (q, r) = (2 *) <$> quotRem x s1+{-# INLINABLE roundHalfFromZero #-}+ -- | [Round down](https://en.wikipedia.org/wiki/Rounding#Rounding_down) rounding -- startegy. This the strategy that is implemented by `floor`. Round towards minus -- infinity:@@ -497,23 +641,34 @@      forall m r s. (MonadThrow m, KnownNat s)   => Scientific   -> m (Decimal r s Integer)-fromScientificDecimal num-  | point10 > s = throwM Underflow-  | otherwise = pure (Decimal (coefficient num * 10 ^ (s - point10)))+fromScientificDecimal numNonNormal+  | exp10 > s = throwM Underflow+  | otherwise = pure (Decimal (coefficient num * 10 ^ (s - exp10)))   where-      s = natVal (Proxy :: Proxy s)-      point10 = toInteger (negate (base10Exponent num))+    num = normalize numNonNormal+    s = natVal (Proxy :: Proxy s)+    exp10 = negate (toInteger (base10Exponent num)) --- | Convert from Scientific to Decimal while checking for Overflow/Underflow+-- | Convert from Scientific to bounded Decimal while checking for Overflow/Underflow -- -- @since 0.1.0 fromScientificDecimalBounded ::      forall m r s p. (MonadThrow m, Integral p, Bounded p, KnownNat s)   => Scientific   -> m (Decimal r s p)-fromScientificDecimalBounded num = do-  Decimal integer :: Decimal r s Integer <- fromScientificDecimal num-  Decimal <$> fromIntegerBounded integer+fromScientificDecimalBounded numNonNormal = do+  when (coeff < toInteger (minBound :: p) || exp10 > s) $ throwM Underflow+  when (coeff > imax || posExp10 > upperExponentBound || scaledCoeff > imax) $ throwM Overflow+  pure (Decimal (fromInteger scaledCoeff))+  where+    num = normalize numNonNormal+    s = natVal (Proxy :: Proxy s)+    posExp10 = toInteger (base10Exponent num)+    exp10 = negate posExp10+    imax = toInteger (maxBound :: p)+    coeff = coefficient num+    scaledCoeff = coefficient num * 10 ^ (s - exp10)+    upperExponentBound = ceiling (logBase 10 $ fromIntegral (maxBound :: p) :: Double) - s   type family FixedScale e :: Nat
src/Numeric/Decimal/BoundedArithmetic.hs view
@@ -7,6 +7,7 @@   , arithM   , arithMaybe   , arithEither+  , arithError   -- * Bounded   , plusBounded   , minusBounded@@ -20,12 +21,16 @@  import Control.Exception import Control.Monad.Catch+import GHC.Stack  -- | Monad for performing safe computation data Arith a   = Arith !a   | ArithError !SomeException +instance Bounded a => Bounded (Arith a) where+  maxBound = Arith maxBound+  minBound = Arith minBound  -- | Convert `Arith` computation to any `MonadThrow` --@@ -55,6 +60,17 @@ -- @since 0.2.0 arithEither :: Arith a -> Either SomeException a arithEither = arithM+++-- | Throws a `userError` on any `Arith` failure. Should only be used as a helper for+-- testing and development.+--+-- @since 0.2.1+arithError :: HasCallStack => Arith a -> a+arithError = \case+  Arith a -> a+  ArithError exc -> error $ displayException exc+   instance Show a => Show (Arith a) where
src/Numeric/Decimal/Internal.hs view
@@ -4,7 +4,6 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE KindSignatures #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE ScopedTypeVariables #-}@@ -437,7 +436,7 @@   {-# INLINABLE signum #-}   abs = (>>= absDecimalBounded)   {-# INLINABLE abs #-}-  fromInteger = fmap Decimal . fromIntegerScaleBounded (Proxy :: Proxy s)+  fromInteger = fromIntegerDecimalBoundedIntegral   {-# INLINABLE fromInteger #-}  instance (KnownNat s) => Num (Arith (Decimal r s Int8)) where@@ -451,7 +450,7 @@   {-# INLINABLE signum #-}   abs = (>>= absDecimalBounded)   {-# INLINABLE abs #-}-  fromInteger = fmap Decimal . fromIntegerScaleBounded (Proxy :: Proxy s)+  fromInteger = fromIntegerDecimalBoundedIntegral   {-# INLINABLE fromInteger #-}  instance (KnownNat s) => Num (Arith (Decimal r s Int16)) where@@ -465,7 +464,7 @@   {-# INLINABLE signum #-}   abs = (>>= absDecimalBounded)   {-# INLINABLE abs #-}-  fromInteger = fmap Decimal . fromIntegerScaleBounded (Proxy :: Proxy s)+  fromInteger = fromIntegerDecimalBoundedIntegral   {-# INLINABLE fromInteger #-}  instance (KnownNat s) => Num (Arith (Decimal r s Int32)) where@@ -479,7 +478,7 @@   {-# INLINABLE signum #-}   abs = (>>= absDecimalBounded)   {-# INLINABLE abs #-}-  fromInteger = fmap Decimal . fromIntegerScaleBounded (Proxy :: Proxy s)+  fromInteger = fromIntegerDecimalBoundedIntegral   {-# INLINABLE fromInteger #-}  instance (KnownNat s) => Num (Arith (Decimal r s Int64)) where@@ -493,7 +492,7 @@   {-# INLINABLE signum #-}   abs = (>>= absDecimalBounded)   {-# INLINABLE abs #-}-  fromInteger = fmap Decimal . fromIntegerScaleBounded (Proxy :: Proxy s)+  fromInteger = fromIntegerDecimalBoundedIntegral   {-# INLINABLE fromInteger #-}  instance (KnownNat s) => Num (Arith (Decimal r s Word)) where@@ -507,7 +506,7 @@   {-# INLINABLE signum #-}   abs = id   {-# INLINABLE abs #-}-  fromInteger = fmap Decimal . fromIntegerScaleBounded (Proxy :: Proxy s)+  fromInteger = fromIntegerDecimalBoundedIntegral   {-# INLINABLE fromInteger #-}  instance (KnownNat s) => Num (Arith (Decimal r s Word8)) where@@ -521,7 +520,7 @@   {-# INLINABLE signum #-}   abs = id   {-# INLINABLE abs #-}-  fromInteger = fmap Decimal . fromIntegerScaleBounded (Proxy :: Proxy s)+  fromInteger = fromIntegerDecimalBoundedIntegral   {-# INLINABLE fromInteger #-}  instance (KnownNat s) => Num (Arith (Decimal r s Word16)) where@@ -535,7 +534,7 @@   {-# INLINABLE signum #-}   abs = id   {-# INLINABLE abs #-}-  fromInteger = fmap Decimal . fromIntegerScaleBounded (Proxy :: Proxy s)+  fromInteger = fromIntegerDecimalBoundedIntegral   {-# INLINABLE fromInteger #-}  instance (KnownNat s) => Num (Arith (Decimal r s Word32)) where@@ -549,7 +548,7 @@   {-# INLINABLE signum #-}   abs = id   {-# INLINABLE abs #-}-  fromInteger = fmap Decimal . fromIntegerScaleBounded (Proxy :: Proxy s)+  fromInteger = fromIntegerDecimalBoundedIntegral   {-# INLINABLE fromInteger #-}  instance (KnownNat s) => Num (Arith (Decimal r s Word64)) where@@ -563,7 +562,7 @@   {-# INLINABLE signum #-}   abs = id   {-# INLINABLE abs #-}-  fromInteger = fmap Decimal . fromIntegerScaleBounded (Proxy :: Proxy s)+  fromInteger = fromIntegerDecimalBoundedIntegral   {-# INLINABLE fromInteger #-}  instance (KnownNat s) => Fractional (Arith (Decimal r s Int)) where@@ -587,7 +586,7 @@ instance (KnownNat s) => Fractional (Arith (Decimal r s Int32)) where   (/) = bindM2 divideDecimalBoundedWithoutLoss   {-# INLINABLE (/) #-}-  fromRational  =fromRationalDecimalBoundedWithoutLoss+  fromRational = fromRationalDecimalBoundedWithoutLoss   {-# INLINABLE fromRational #-}  @@ -699,6 +698,7 @@       pure (Decimal q, Decimal r) {-# INLINABLE quotRemDecimalBounded #-} + fromIntegerScaleBounded ::      forall m a s. (MonadThrow m, Integral a, Bounded a, KnownNat s)   => Proxy s@@ -722,6 +722,10 @@ {-# INLINABLE fromIntegersScaleBounded #-}  +-- | Convert an Integer to a Decimal backed by a bounded integral while doing proper+-- scaling and checking the bounds.+--+-- @since 0.2.0 fromIntegerDecimalBoundedIntegral ::      forall m r s p. (MonadThrow m, Integral p, Bounded p, KnownNat s)   => Integer
tests/Numeric/DecimalSpec.hs view
@@ -172,6 +172,8 @@      , Round RoundHalfUp a      , Round RoundHalfDown a      , Round RoundHalfEven a+     , Round RoundHalfToZero a+     , Round RoundHalfFromZero a      , Round RoundDown a      , Round RoundToZero a      )@@ -235,6 +237,8 @@      , Round RoundHalfUp p      , Round RoundHalfDown p      , Round RoundHalfEven p+     , Round RoundHalfToZero p+     , Round RoundHalfFromZero p      , Round RoundDown p      , Round RoundToZero p      )@@ -249,9 +253,15 @@   prop (propNamePrefix . showsDecimalType @RoundHalfEven @(s + k) @p $ "") $     prop_Rounding @RoundHalfEven @s @k @p     (roundHalfEvenTo (fromIntegral (natVal (Proxy :: Proxy s))))+  prop (propNamePrefix . showsDecimalType @RoundHalfToZero @(s + k) @p $ "") $+    prop_Rounding @RoundHalfToZero @s @k @p+    (roundHalfToZeroTo (fromIntegral (natVal (Proxy :: Proxy s))))+  prop (propNamePrefix . showsDecimalType @RoundHalfFromZero @(s + k) @p $ "") $+    prop_Rounding @RoundHalfFromZero @s @k @p+    (roundHalfFromZeroTo (fromIntegral (natVal (Proxy :: Proxy s))))   prop (propNamePrefix . showsDecimalType @RoundToZero @(s + k) @p $ "") $     prop_Rounding @RoundToZero @s @k @p-    (roundRoundToZeroTo (fromIntegral (natVal (Proxy :: Proxy s))))+    (roundToZeroTo (fromIntegral (natVal (Proxy :: Proxy s))))   prop (propNamePrefix . showsDecimalType @RoundDown @(s + k) @p $ "") $     prop_Rounding @RoundDown @s @k @p     (roundFloorTo (fromIntegral (natVal (Proxy :: Proxy s))))@@ -275,7 +285,7 @@       throwDecimal (fromRationalDecimalWithoutLoss (roundTo r))  showsDecimalType ::-     forall r (s :: Nat) p. (Typeable r, Typeable s, Typeable p)+     forall r (s :: Nat) p. (Typeable r, KnownNat s, Typeable p)   => ShowS showsDecimalType = ("(Decimal " ++)                    . showsType @r . (' ':)@@ -423,14 +433,18 @@   where     s10 = 10 ^ to :: Integer -roundRoundToZeroTo :: Natural -> Rational -> Rational-roundRoundToZeroTo to rational = (truncate (rational * (s10 % 1)) :: Integer) % s10+roundToZeroTo :: Natural -> Rational -> Rational+roundToZeroTo to rational = (truncate (rational * (s10 % 1)) :: Integer) % s10   where     s10 = 10 ^ to :: Integer --- Use for testing once HalfAwayFromZero is implemented-_roundCommercial :: Natural -> Rational -> Rational-_roundCommercial to rational+roundHalfToZeroTo :: Natural -> Rational -> Rational+roundHalfToZeroTo to rational+  | rational < 0 = negate (roundHalfDownTo to (negate rational))+  | otherwise = roundHalfDownTo to rational++roundHalfFromZeroTo :: Natural -> Rational -> Rational+roundHalfFromZeroTo to rational   | rational < 0 = negate (roundPositive (negate rational))   | otherwise = roundPositive rational   where
tests/doctests.hs view
@@ -1,12 +1,16 @@+{-# LANGUAGE CPP #-} module Main where -import Build_doctests (flags, pkgs, module_sources)-import Data.Foldable (traverse_)+#if __GLASGOW_HASKELL__ >= 802+ import Test.DocTest (doctest)  main :: IO ()-main = do-    traverse_ putStrLn args-    doctest args-  where-    args = flags ++ pkgs ++ module_sources+main = doctest ["src"]++#else++main :: IO ()+main = putStrLn "\nDoctests are not supported for older ghc version\n"++#endif