{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}
module Numeric.Decimal
  (
  -- * Arithmetic
    module Numeric.Decimal.BoundedArithmetic
  , module Numeric.Decimal.Internal
  -- * Rounding
  -- ** Round half up
  , RoundHalfUp
  , roundHalfUp
  -- ** Round half down
  , RoundHalfDown
  , roundHalfDown
  -- ** Round half even
  , RoundHalfEven
  , roundHalfEven
  -- ** Round half to zero
  , RoundHalfToZero
  , roundHalfToZero
  -- ** Round half from zero
  , RoundHalfFromZero
  , roundHalfFromZero
  -- ** Round down
  , RoundDown
  , Floor
  , roundDown
  -- ** Round towards zero
  , RoundToZero
  , Truncate
  , roundToZero
  -- * Operations
  , decimalList
  , sumDecimalBounded
  , productDecimalBoundedWithRounding
  -- * Conversion
  -- ** Fixed
  , FixedScale
  , toFixedDecimal
  , fromFixedDecimal
  , fromFixedDecimalBounded
  -- ** Scientific
  , toScientificDecimal
  , fromScientificDecimal
  , fromScientificDecimalBounded
  ) where

import Control.Exception
import Control.Monad
import Control.Monad.Catch
import Data.Coerce
import Data.Fixed
import Data.Int
import Data.Proxy
import Data.Scientific
import Data.Word
import GHC.TypeLits
import Numeric.Decimal.BoundedArithmetic
import Numeric.Decimal.Internal


-- | [Round half up](https://en.wikipedia.org/wiki/Rounding#Round_half_up) rounding strategy:
--
-- >>> :set -XDataKinds
-- >>> roundDecimal <$> (3.740 :: Arith (Decimal RoundHalfUp 3 Int)) :: Arith (Decimal RoundHalfUp 1 Int)
-- Arith 3.7
--
-- Or with a bit more concise approach using `arithRoundD` and @TypeApplications@:
--
-- >>> :set -XTypeApplications
-- >>> arithRoundD @1 @RoundHalfUp @3 @Int 3.740
-- Arith 3.7
-- >>> arithRoundD @1 @RoundHalfUp @3 @Int 3.749
-- Arith 3.7
-- >>> arithRoundD @1 @RoundHalfUp @3 @Int 3.750
-- Arith 3.8
-- >>> arithRoundD @1 @RoundHalfUp @3 @Int 3.751
-- Arith 3.8
-- >>> arithRoundD @1 @RoundHalfUp @3 @Int 3.760
-- Arith 3.8
-- >>> arithRoundD @1 @RoundHalfUp @3 @Int (-3.740)
-- Arith -3.7
-- >>> arithRoundD @1 @RoundHalfUp @3 @Int (-3.749)
-- Arith -3.7
-- >>> arithRoundD @1 @RoundHalfUp @3 @Int (-3.750)
-- Arith -3.7
-- >>> arithRoundD @1 @RoundHalfUp @3 @Int (-3.751)
-- Arith -3.8
-- >>> arithRoundD @1 @RoundHalfUp @3 @Int (-3.760)
-- Arith -3.8
--
-- @since 0.1.0
data RoundHalfUp

instance Round RoundHalfUp Integer where
  roundDecimal :: Decimal RoundHalfUp (n + k) Integer
-> Decimal RoundHalfUp n Integer
roundDecimal = Decimal RoundHalfUp (n + k) Integer
-> Decimal RoundHalfUp n Integer
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundHalfUp
  {-# INLINABLE roundDecimal #-}
instance Round RoundHalfUp Int where
  roundDecimal :: Decimal RoundHalfUp (n + k) Int -> Decimal RoundHalfUp n Int
roundDecimal = Decimal RoundHalfUp (n + k) Int -> Decimal RoundHalfUp n Int
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundHalfUp
  {-# INLINABLE roundDecimal #-}
instance Round RoundHalfUp Int8 where
  roundDecimal :: Decimal RoundHalfUp (n + k) Int8 -> Decimal RoundHalfUp n Int8
roundDecimal = Decimal RoundHalfUp (n + k) Int8 -> Decimal RoundHalfUp n Int8
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundHalfUp
  {-# INLINABLE roundDecimal #-}
instance Round RoundHalfUp Int16 where
  roundDecimal :: Decimal RoundHalfUp (n + k) Int16 -> Decimal RoundHalfUp n Int16
roundDecimal = Decimal RoundHalfUp (n + k) Int16 -> Decimal RoundHalfUp n Int16
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundHalfUp
  {-# INLINABLE roundDecimal #-}
instance Round RoundHalfUp Int32 where
  roundDecimal :: Decimal RoundHalfUp (n + k) Int32 -> Decimal RoundHalfUp n Int32
roundDecimal = Decimal RoundHalfUp (n + k) Int32 -> Decimal RoundHalfUp n Int32
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundHalfUp
  {-# INLINABLE roundDecimal #-}
instance Round RoundHalfUp Int64 where
  roundDecimal :: Decimal RoundHalfUp (n + k) Int64 -> Decimal RoundHalfUp n Int64
roundDecimal = Decimal RoundHalfUp (n + k) Int64 -> Decimal RoundHalfUp n Int64
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundHalfUp
  {-# INLINABLE roundDecimal #-}
instance Round RoundHalfUp Word where
  roundDecimal :: Decimal RoundHalfUp (n + k) Word -> Decimal RoundHalfUp n Word
roundDecimal = Decimal RoundHalfUp (n + k) Word -> Decimal RoundHalfUp n Word
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundHalfUp
  {-# INLINABLE roundDecimal #-}
instance Round RoundHalfUp Word8 where
  roundDecimal :: Decimal RoundHalfUp (n + k) Word8 -> Decimal RoundHalfUp n Word8
roundDecimal = Decimal RoundHalfUp (n + k) Word8 -> Decimal RoundHalfUp n Word8
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundHalfUp
  {-# INLINABLE roundDecimal #-}
instance Round RoundHalfUp Word16 where
  roundDecimal :: Decimal RoundHalfUp (n + k) Word16 -> Decimal RoundHalfUp n Word16
roundDecimal = Decimal RoundHalfUp (n + k) Word16 -> Decimal RoundHalfUp n Word16
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundHalfUp
  {-# INLINABLE roundDecimal #-}
instance Round RoundHalfUp Word32 where
  roundDecimal :: Decimal RoundHalfUp (n + k) Word32 -> Decimal RoundHalfUp n Word32
roundDecimal = Decimal RoundHalfUp (n + k) Word32 -> Decimal RoundHalfUp n Word32
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundHalfUp
  {-# INLINABLE roundDecimal #-}
instance Round RoundHalfUp Word64 where
  roundDecimal :: Decimal RoundHalfUp (n + k) Word64 -> Decimal RoundHalfUp n Word64
roundDecimal = Decimal RoundHalfUp (n + k) Word64 -> Decimal RoundHalfUp n Word64
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundHalfUp
  {-# INLINABLE roundDecimal #-}

roundHalfUp :: forall r n k p . (Integral p, KnownNat k) => Decimal r (n + k) p -> Decimal r n p
roundHalfUp :: Decimal r (n + k) p -> Decimal r n p
roundHalfUp (Decimal p
x)
    | Int
k Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0                     = p -> Decimal r n p
forall r (s :: Nat) p. p -> Decimal r s p
Decimal p
x
    | p
r p -> p -> Bool
forall a. Ord a => a -> a -> Bool
>= p
s1                    = p -> Decimal r n p
forall r (s :: Nat) p. p -> Decimal r s p
Decimal (p
q p -> p -> p
forall a. Num a => a -> a -> a
+ p
1)
    | p -> p
forall a. Num a => a -> a
signum p
r p -> p -> Bool
forall a. Ord a => a -> a -> Bool
< p
0 Bool -> Bool -> Bool
&& p -> p
forall a. Num a => a -> a
abs p
r p -> p -> Bool
forall a. Ord a => a -> a -> Bool
> p
s1 = p -> Decimal r n p
forall r (s :: Nat) p. p -> Decimal r s p
Decimal (p
q p -> p -> p
forall a. Num a => a -> a -> a
- p
1)
    | Bool
otherwise                  = p -> Decimal r n p
forall r (s :: Nat) p. p -> Decimal r s p
Decimal p
q
    where
      k :: Int
k = Integer -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Proxy k -> Integer
forall (n :: Nat) (proxy :: Nat -> *).
KnownNat n =>
proxy n -> Integer
natVal (Proxy k
forall k (t :: k). Proxy t
Proxy :: Proxy k)) :: Int
      s1 :: p
s1 = p
10 p -> Int -> p
forall a b. (Num a, Integral b) => a -> b -> a
^ Int
k
      (p
q, p
r) = (p
2 p -> p -> p
forall a. Num a => a -> a -> a
*) (p -> p) -> (p, p) -> (p, p)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> p -> p -> (p, p)
forall a. Integral a => a -> a -> (a, a)
quotRem p
x p
s1
{-# INLINABLE roundHalfUp #-}

-- | [Round half down](https://en.wikipedia.org/wiki/Rounding#Round_half_down) rounding strategy:
--
-- >>> :set -XDataKinds
-- >>> :set -XTypeApplications
-- >>> arithRoundD @1 @RoundHalfDown @3 @Int 3.740
-- Arith 3.7
-- >>> arithRoundD @1 @RoundHalfDown @3 @Int 3.749
-- Arith 3.7
-- >>> arithRoundD @1 @RoundHalfDown @3 @Int 3.750
-- Arith 3.7
-- >>> arithRoundD @1 @RoundHalfDown @3 @Int 3.751
-- Arith 3.8
-- >>> arithRoundD @1 @RoundHalfDown @3 @Int 3.760
-- Arith 3.8
-- >>> arithRoundD @1 @RoundHalfDown @3 @Int (-3.740)
-- Arith -3.7
-- >>> arithRoundD @1 @RoundHalfDown @3 @Int (-3.749)
-- Arith -3.7
-- >>> arithRoundD @1 @RoundHalfDown @3 @Int (-3.750)
-- Arith -3.8
-- >>> arithRoundD @1 @RoundHalfDown @3 @Int (-3.751)
-- Arith -3.8
-- >>> arithRoundD @1 @RoundHalfDown @3 @Int (-3.760)
-- Arith -3.8
--
-- @since 0.2.0
data RoundHalfDown

instance Round RoundHalfDown Integer where
  roundDecimal :: Decimal RoundHalfDown (n + k) Integer
-> Decimal RoundHalfDown n Integer
roundDecimal = Decimal RoundHalfDown (n + k) Integer
-> Decimal RoundHalfDown n Integer
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundHalfDown
  {-# INLINABLE roundDecimal #-}
instance Round RoundHalfDown Int where
  roundDecimal :: Decimal RoundHalfDown (n + k) Int -> Decimal RoundHalfDown n Int
roundDecimal = Decimal RoundHalfDown (n + k) Int -> Decimal RoundHalfDown n Int
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundHalfDown
  {-# INLINABLE roundDecimal #-}
instance Round RoundHalfDown Int8 where
  roundDecimal :: Decimal RoundHalfDown (n + k) Int8 -> Decimal RoundHalfDown n Int8
roundDecimal = Decimal RoundHalfDown (n + k) Int8 -> Decimal RoundHalfDown n Int8
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundHalfDown
  {-# INLINABLE roundDecimal #-}
instance Round RoundHalfDown Int16 where
  roundDecimal :: Decimal RoundHalfDown (n + k) Int16
-> Decimal RoundHalfDown n Int16
roundDecimal = Decimal RoundHalfDown (n + k) Int16
-> Decimal RoundHalfDown n Int16
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundHalfDown
  {-# INLINABLE roundDecimal #-}
instance Round RoundHalfDown Int32 where
  roundDecimal :: Decimal RoundHalfDown (n + k) Int32
-> Decimal RoundHalfDown n Int32
roundDecimal = Decimal RoundHalfDown (n + k) Int32
-> Decimal RoundHalfDown n Int32
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundHalfDown
  {-# INLINABLE roundDecimal #-}
instance Round RoundHalfDown Int64 where
  roundDecimal :: Decimal RoundHalfDown (n + k) Int64
-> Decimal RoundHalfDown n Int64
roundDecimal = Decimal RoundHalfDown (n + k) Int64
-> Decimal RoundHalfDown n Int64
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundHalfDown
  {-# INLINABLE roundDecimal #-}
instance Round RoundHalfDown Word where
  roundDecimal :: Decimal RoundHalfDown (n + k) Word -> Decimal RoundHalfDown n Word
roundDecimal = Decimal RoundHalfDown (n + k) Word -> Decimal RoundHalfDown n Word
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundHalfDown
  {-# INLINABLE roundDecimal #-}
instance Round RoundHalfDown Word8 where
  roundDecimal :: Decimal RoundHalfDown (n + k) Word8
-> Decimal RoundHalfDown n Word8
roundDecimal = Decimal RoundHalfDown (n + k) Word8
-> Decimal RoundHalfDown n Word8
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundHalfDown
  {-# INLINABLE roundDecimal #-}
instance Round RoundHalfDown Word16 where
  roundDecimal :: Decimal RoundHalfDown (n + k) Word16
-> Decimal RoundHalfDown n Word16
roundDecimal = Decimal RoundHalfDown (n + k) Word16
-> Decimal RoundHalfDown n Word16
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundHalfDown
  {-# INLINABLE roundDecimal #-}
instance Round RoundHalfDown Word32 where
  roundDecimal :: Decimal RoundHalfDown (n + k) Word32
-> Decimal RoundHalfDown n Word32
roundDecimal = Decimal RoundHalfDown (n + k) Word32
-> Decimal RoundHalfDown n Word32
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundHalfDown
  {-# INLINABLE roundDecimal #-}
instance Round RoundHalfDown Word64 where
  roundDecimal :: Decimal RoundHalfDown (n + k) Word64
-> Decimal RoundHalfDown n Word64
roundDecimal = Decimal RoundHalfDown (n + k) Word64
-> Decimal RoundHalfDown n Word64
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundHalfDown
  {-# INLINABLE roundDecimal #-}

roundHalfDown :: forall r n k p . (Integral p, KnownNat k) => Decimal r (n + k) p -> Decimal r n p
roundHalfDown :: Decimal r (n + k) p -> Decimal r n p
roundHalfDown (Decimal p
x)
    | Int
k Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0                      = p -> Decimal r n p
forall r (s :: Nat) p. p -> Decimal r s p
Decimal p
x
    | p
r p -> p -> Bool
forall a. Ord a => a -> a -> Bool
> p
s1                      = p -> Decimal r n p
forall r (s :: Nat) p. p -> Decimal r s p
Decimal (p
q p -> p -> p
forall a. Num a => a -> a -> a
+ p
1)
    | p -> p
forall a. Num a => a -> a
signum p
r p -> p -> Bool
forall a. Ord a => a -> a -> Bool
< p
0 Bool -> Bool -> Bool
&& p -> p
forall a. Num a => a -> a
abs p
r p -> p -> Bool
forall a. Ord a => a -> a -> Bool
>= p
s1 = p -> Decimal r n p
forall r (s :: Nat) p. p -> Decimal r s p
Decimal (p
q p -> p -> p
forall a. Num a => a -> a -> a
- p
1)
    | Bool
otherwise                   = p -> Decimal r n p
forall r (s :: Nat) p. p -> Decimal r s p
Decimal p
q
    where
      k :: Int
k = Integer -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Proxy k -> Integer
forall (n :: Nat) (proxy :: Nat -> *).
KnownNat n =>
proxy n -> Integer
natVal (Proxy k
forall k (t :: k). Proxy t
Proxy :: Proxy k)) :: Int
      s1 :: p
s1 = p
10 p -> Int -> p
forall a b. (Num a, Integral b) => a -> b -> a
^ Int
k
      (p
q, p
r) = (p
2 p -> p -> p
forall a. Num a => a -> a -> a
*) (p -> p) -> (p, p) -> (p, p)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> p -> p -> (p, p)
forall a. Integral a => a -> a -> (a, a)
quotRem p
x p
s1
{-# INLINABLE roundHalfDown #-}

-- | [Round half even](https://en.wikipedia.org/wiki/Rounding#Round_half_to_even) rounding
-- strategy. If the fractional part of x is 0.5, then y is the even integer nearest to
-- x. This is the default rounding strategy in Haskell implemented by `round`.
--
-- >>> :set -XDataKinds
-- >>> :set -XTypeApplications
-- >>> arithRoundD @1 @RoundHalfEven @3 @Int 3.650
-- Arith 3.6
-- >>> arithRoundD @1 @RoundHalfEven @3 @Int 3.740
-- Arith 3.7
-- >>> arithRoundD @1 @RoundHalfEven @3 @Int 3.749
-- Arith 3.7
-- >>> arithRoundD @1 @RoundHalfEven @3 @Int 3.750
-- Arith 3.8
-- >>> arithRoundD @1 @RoundHalfEven @3 @Int 3.751
-- Arith 3.8
-- >>> arithRoundD @1 @RoundHalfEven @3 @Int 3.760
-- Arith 3.8
-- >>> arithRoundD @1 @RoundHalfEven @3 @Int (-3.650)
-- Arith -3.6
-- >>> arithRoundD @1 @RoundHalfEven @3 @Int (-3.740)
-- Arith -3.7
-- >>> arithRoundD @1 @RoundHalfEven @3 @Int (-3.749)
-- Arith -3.7
-- >>> arithRoundD @1 @RoundHalfEven @3 @Int (-3.750)
-- Arith -3.8
-- >>> arithRoundD @1 @RoundHalfEven @3 @Int (-3.751)
-- Arith -3.8
-- >>> arithRoundD @1 @RoundHalfEven @3 @Int (-3.760)
-- Arith -3.8
--
-- @since 0.2.0
data RoundHalfEven

instance Round RoundHalfEven Integer where
  roundDecimal :: Decimal RoundHalfEven (n + k) Integer
-> Decimal RoundHalfEven n Integer
roundDecimal = Decimal RoundHalfEven (n + k) Integer
-> Decimal RoundHalfEven n Integer
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundHalfEven
  {-# INLINABLE roundDecimal #-}
instance Round RoundHalfEven Int where
  roundDecimal :: Decimal RoundHalfEven (n + k) Int -> Decimal RoundHalfEven n Int
roundDecimal = Decimal RoundHalfEven (n + k) Int -> Decimal RoundHalfEven n Int
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundHalfEven
  {-# INLINABLE roundDecimal #-}
instance Round RoundHalfEven Int8 where
  roundDecimal :: Decimal RoundHalfEven (n + k) Int8 -> Decimal RoundHalfEven n Int8
roundDecimal = Decimal RoundHalfEven (n + k) Int8 -> Decimal RoundHalfEven n Int8
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundHalfEven
  {-# INLINABLE roundDecimal #-}
instance Round RoundHalfEven Int16 where
  roundDecimal :: Decimal RoundHalfEven (n + k) Int16
-> Decimal RoundHalfEven n Int16
roundDecimal = Decimal RoundHalfEven (n + k) Int16
-> Decimal RoundHalfEven n Int16
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundHalfEven
  {-# INLINABLE roundDecimal #-}
instance Round RoundHalfEven Int32 where
  roundDecimal :: Decimal RoundHalfEven (n + k) Int32
-> Decimal RoundHalfEven n Int32
roundDecimal = Decimal RoundHalfEven (n + k) Int32
-> Decimal RoundHalfEven n Int32
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundHalfEven
  {-# INLINABLE roundDecimal #-}
instance Round RoundHalfEven Int64 where
  roundDecimal :: Decimal RoundHalfEven (n + k) Int64
-> Decimal RoundHalfEven n Int64
roundDecimal = Decimal RoundHalfEven (n + k) Int64
-> Decimal RoundHalfEven n Int64
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundHalfEven
  {-# INLINABLE roundDecimal #-}
instance Round RoundHalfEven Word where
  roundDecimal :: Decimal RoundHalfEven (n + k) Word -> Decimal RoundHalfEven n Word
roundDecimal = Decimal RoundHalfEven (n + k) Word -> Decimal RoundHalfEven n Word
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundHalfEven
  {-# INLINABLE roundDecimal #-}
instance Round RoundHalfEven Word8 where
  roundDecimal :: Decimal RoundHalfEven (n + k) Word8
-> Decimal RoundHalfEven n Word8
roundDecimal = Decimal RoundHalfEven (n + k) Word8
-> Decimal RoundHalfEven n Word8
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundHalfEven
  {-# INLINABLE roundDecimal #-}
instance Round RoundHalfEven Word16 where
  roundDecimal :: Decimal RoundHalfEven (n + k) Word16
-> Decimal RoundHalfEven n Word16
roundDecimal = Decimal RoundHalfEven (n + k) Word16
-> Decimal RoundHalfEven n Word16
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundHalfEven
  {-# INLINABLE roundDecimal #-}
instance Round RoundHalfEven Word32 where
  roundDecimal :: Decimal RoundHalfEven (n + k) Word32
-> Decimal RoundHalfEven n Word32
roundDecimal = Decimal RoundHalfEven (n + k) Word32
-> Decimal RoundHalfEven n Word32
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundHalfEven
  {-# INLINABLE roundDecimal #-}
instance Round RoundHalfEven Word64 where
  roundDecimal :: Decimal RoundHalfEven (n + k) Word64
-> Decimal RoundHalfEven n Word64
roundDecimal = Decimal RoundHalfEven (n + k) Word64
-> Decimal RoundHalfEven n Word64
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundHalfEven
  {-# INLINABLE roundDecimal #-}

roundHalfEven :: forall r n k p . (Integral p, KnownNat k) => Decimal r (n + k) p -> Decimal r n p
roundHalfEven :: Decimal r (n + k) p -> Decimal r n p
roundHalfEven (Decimal p
x)
    | Int
k Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0                     = p -> Decimal r n p
forall r (s :: Nat) p. p -> Decimal r s p
Decimal p
x
    | p -> p
forall a. Num a => a -> a
abs p
r p -> p -> Bool
forall a. Eq a => a -> a -> Bool
== p
s1 Bool -> Bool -> Bool
&& p -> Bool
forall a. Integral a => a -> Bool
odd p
q       = p -> Decimal r n p
forall r (s :: Nat) p. p -> Decimal r s p
Decimal (p
q p -> p -> p
forall a. Num a => a -> a -> a
+ p -> p
forall a. Num a => a -> a
signum p
r)
    | p -> p
forall a. Num a => a -> a
abs p
r p -> p -> Bool
forall a. Eq a => a -> a -> Bool
== p
s1                = p -> Decimal r n p
forall r (s :: Nat) p. p -> Decimal r s p
Decimal p
q
    | p
r p -> p -> Bool
forall a. Ord a => a -> a -> Bool
> p
s1                     = p -> Decimal r n p
forall r (s :: Nat) p. p -> Decimal r s p
Decimal (p
q p -> p -> p
forall a. Num a => a -> a -> a
+ p
1)
    | p -> p
forall a. Num a => a -> a
signum p
r p -> p -> Bool
forall a. Ord a => a -> a -> Bool
< p
0 Bool -> Bool -> Bool
&& p -> p
forall a. Num a => a -> a
abs p
r p -> p -> Bool
forall a. Ord a => a -> a -> Bool
> p
s1 = p -> Decimal r n p
forall r (s :: Nat) p. p -> Decimal r s p
Decimal (p
q p -> p -> p
forall a. Num a => a -> a -> a
- p
1)
    | Bool
otherwise                  = p -> Decimal r n p
forall r (s :: Nat) p. p -> Decimal r s p
Decimal p
q
    where
      k :: Int
k = Integer -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Proxy k -> Integer
forall (n :: Nat) (proxy :: Nat -> *).
KnownNat n =>
proxy n -> Integer
natVal (Proxy k
forall k (t :: k). Proxy t
Proxy :: Proxy k)) :: Int
      s1 :: p
s1 = p
10 p -> Int -> p
forall a b. (Num a, Integral b) => a -> b -> a
^ Int
k
      (p
q, p
r) = (p
2 p -> p -> p
forall a. Num a => a -> a -> a
*) (p -> p) -> (p, p) -> (p, p)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> p -> p -> (p, p)
forall a. Integral a => a -> a -> (a, a)
quotRem p
x p
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 :: Decimal RoundHalfToZero (n + k) Integer
-> Decimal RoundHalfToZero n Integer
roundDecimal = Decimal RoundHalfToZero (n + k) Integer
-> Decimal RoundHalfToZero n Integer
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundHalfToZero
  {-# INLINABLE roundDecimal #-}
instance Round RoundHalfToZero Int where
  roundDecimal :: Decimal RoundHalfToZero (n + k) Int
-> Decimal RoundHalfToZero n Int
roundDecimal = Decimal RoundHalfToZero (n + k) Int
-> Decimal RoundHalfToZero n Int
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundHalfToZero
  {-# INLINABLE roundDecimal #-}
instance Round RoundHalfToZero Int8 where
  roundDecimal :: Decimal RoundHalfToZero (n + k) Int8
-> Decimal RoundHalfToZero n Int8
roundDecimal = Decimal RoundHalfToZero (n + k) Int8
-> Decimal RoundHalfToZero n Int8
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundHalfToZero
  {-# INLINABLE roundDecimal #-}
instance Round RoundHalfToZero Int16 where
  roundDecimal :: Decimal RoundHalfToZero (n + k) Int16
-> Decimal RoundHalfToZero n Int16
roundDecimal = Decimal RoundHalfToZero (n + k) Int16
-> Decimal RoundHalfToZero n Int16
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundHalfToZero
  {-# INLINABLE roundDecimal #-}
instance Round RoundHalfToZero Int32 where
  roundDecimal :: Decimal RoundHalfToZero (n + k) Int32
-> Decimal RoundHalfToZero n Int32
roundDecimal = Decimal RoundHalfToZero (n + k) Int32
-> Decimal RoundHalfToZero n Int32
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundHalfToZero
  {-# INLINABLE roundDecimal #-}
instance Round RoundHalfToZero Int64 where
  roundDecimal :: Decimal RoundHalfToZero (n + k) Int64
-> Decimal RoundHalfToZero n Int64
roundDecimal = Decimal RoundHalfToZero (n + k) Int64
-> Decimal RoundHalfToZero n Int64
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundHalfToZero
  {-# INLINABLE roundDecimal #-}
instance Round RoundHalfToZero Word where
  roundDecimal :: Decimal RoundHalfToZero (n + k) Word
-> Decimal RoundHalfToZero n Word
roundDecimal = Decimal RoundHalfToZero (n + k) Word
-> Decimal RoundHalfToZero n Word
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundHalfToZero
  {-# INLINABLE roundDecimal #-}
instance Round RoundHalfToZero Word8 where
  roundDecimal :: Decimal RoundHalfToZero (n + k) Word8
-> Decimal RoundHalfToZero n Word8
roundDecimal = Decimal RoundHalfToZero (n + k) Word8
-> Decimal RoundHalfToZero n Word8
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundHalfToZero
  {-# INLINABLE roundDecimal #-}
instance Round RoundHalfToZero Word16 where
  roundDecimal :: Decimal RoundHalfToZero (n + k) Word16
-> Decimal RoundHalfToZero n Word16
roundDecimal = Decimal RoundHalfToZero (n + k) Word16
-> Decimal RoundHalfToZero n Word16
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundHalfToZero
  {-# INLINABLE roundDecimal #-}
instance Round RoundHalfToZero Word32 where
  roundDecimal :: Decimal RoundHalfToZero (n + k) Word32
-> Decimal RoundHalfToZero n Word32
roundDecimal = Decimal RoundHalfToZero (n + k) Word32
-> Decimal RoundHalfToZero n Word32
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundHalfToZero
  {-# INLINABLE roundDecimal #-}
instance Round RoundHalfToZero Word64 where
  roundDecimal :: Decimal RoundHalfToZero (n + k) Word64
-> Decimal RoundHalfToZero n Word64
roundDecimal = Decimal RoundHalfToZero (n + k) Word64
-> Decimal RoundHalfToZero n Word64
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundHalfToZero
  {-# INLINABLE roundDecimal #-}

roundHalfToZero :: forall r n k p . (Integral p, KnownNat k) => Decimal r (n + k) p -> Decimal r n p
roundHalfToZero :: Decimal r (n + k) p -> Decimal r n p
roundHalfToZero (Decimal p
x)
    | Int
k Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0                     = p -> Decimal r n p
forall r (s :: Nat) p. p -> Decimal r s p
Decimal p
x
    | p
r p -> p -> Bool
forall a. Ord a => a -> a -> Bool
> p
s1                     = p -> Decimal r n p
forall r (s :: Nat) p. p -> Decimal r s p
Decimal (p
q p -> p -> p
forall a. Num a => a -> a -> a
+ p
1)
    | p -> p
forall a. Num a => a -> a
signum p
r p -> p -> Bool
forall a. Ord a => a -> a -> Bool
< p
0 Bool -> Bool -> Bool
&& p -> p
forall a. Num a => a -> a
abs p
r p -> p -> Bool
forall a. Ord a => a -> a -> Bool
> p
s1 = p -> Decimal r n p
forall r (s :: Nat) p. p -> Decimal r s p
Decimal (p
q p -> p -> p
forall a. Num a => a -> a -> a
- p
1)
    | Bool
otherwise                  = p -> Decimal r n p
forall r (s :: Nat) p. p -> Decimal r s p
Decimal p
q
    where
      k :: Int
k = Integer -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Proxy k -> Integer
forall (n :: Nat) (proxy :: Nat -> *).
KnownNat n =>
proxy n -> Integer
natVal (Proxy k
forall k (t :: k). Proxy t
Proxy :: Proxy k)) :: Int
      s1 :: p
s1 = p
10 p -> Int -> p
forall a b. (Num a, Integral b) => a -> b -> a
^ Int
k
      (p
q, p
r) = (p
2 p -> p -> p
forall a. Num a => a -> a -> a
*) (p -> p) -> (p, p) -> (p, p)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> p -> p -> (p, p)
forall a. Integral a => a -> a -> (a, a)
quotRem p
x p
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 :: Decimal RoundHalfFromZero (n + k) Integer
-> Decimal RoundHalfFromZero n Integer
roundDecimal = Decimal RoundHalfFromZero (n + k) Integer
-> Decimal RoundHalfFromZero n Integer
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundHalfFromZero
  {-# INLINABLE roundDecimal #-}
instance Round RoundHalfFromZero Int where
  roundDecimal :: Decimal RoundHalfFromZero (n + k) Int
-> Decimal RoundHalfFromZero n Int
roundDecimal = Decimal RoundHalfFromZero (n + k) Int
-> Decimal RoundHalfFromZero n Int
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundHalfFromZero
  {-# INLINABLE roundDecimal #-}
instance Round RoundHalfFromZero Int8 where
  roundDecimal :: Decimal RoundHalfFromZero (n + k) Int8
-> Decimal RoundHalfFromZero n Int8
roundDecimal = Decimal RoundHalfFromZero (n + k) Int8
-> Decimal RoundHalfFromZero n Int8
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundHalfFromZero
  {-# INLINABLE roundDecimal #-}
instance Round RoundHalfFromZero Int16 where
  roundDecimal :: Decimal RoundHalfFromZero (n + k) Int16
-> Decimal RoundHalfFromZero n Int16
roundDecimal = Decimal RoundHalfFromZero (n + k) Int16
-> Decimal RoundHalfFromZero n Int16
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundHalfFromZero
  {-# INLINABLE roundDecimal #-}
instance Round RoundHalfFromZero Int32 where
  roundDecimal :: Decimal RoundHalfFromZero (n + k) Int32
-> Decimal RoundHalfFromZero n Int32
roundDecimal = Decimal RoundHalfFromZero (n + k) Int32
-> Decimal RoundHalfFromZero n Int32
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundHalfFromZero
  {-# INLINABLE roundDecimal #-}
instance Round RoundHalfFromZero Int64 where
  roundDecimal :: Decimal RoundHalfFromZero (n + k) Int64
-> Decimal RoundHalfFromZero n Int64
roundDecimal = Decimal RoundHalfFromZero (n + k) Int64
-> Decimal RoundHalfFromZero n Int64
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundHalfFromZero
  {-# INLINABLE roundDecimal #-}
instance Round RoundHalfFromZero Word where
  roundDecimal :: Decimal RoundHalfFromZero (n + k) Word
-> Decimal RoundHalfFromZero n Word
roundDecimal = Decimal RoundHalfFromZero (n + k) Word
-> Decimal RoundHalfFromZero n Word
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundHalfFromZero
  {-# INLINABLE roundDecimal #-}
instance Round RoundHalfFromZero Word8 where
  roundDecimal :: Decimal RoundHalfFromZero (n + k) Word8
-> Decimal RoundHalfFromZero n Word8
roundDecimal = Decimal RoundHalfFromZero (n + k) Word8
-> Decimal RoundHalfFromZero n Word8
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundHalfFromZero
  {-# INLINABLE roundDecimal #-}
instance Round RoundHalfFromZero Word16 where
  roundDecimal :: Decimal RoundHalfFromZero (n + k) Word16
-> Decimal RoundHalfFromZero n Word16
roundDecimal = Decimal RoundHalfFromZero (n + k) Word16
-> Decimal RoundHalfFromZero n Word16
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundHalfFromZero
  {-# INLINABLE roundDecimal #-}
instance Round RoundHalfFromZero Word32 where
  roundDecimal :: Decimal RoundHalfFromZero (n + k) Word32
-> Decimal RoundHalfFromZero n Word32
roundDecimal = Decimal RoundHalfFromZero (n + k) Word32
-> Decimal RoundHalfFromZero n Word32
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundHalfFromZero
  {-# INLINABLE roundDecimal #-}
instance Round RoundHalfFromZero Word64 where
  roundDecimal :: Decimal RoundHalfFromZero (n + k) Word64
-> Decimal RoundHalfFromZero n Word64
roundDecimal = Decimal RoundHalfFromZero (n + k) Word64
-> Decimal RoundHalfFromZero n Word64
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundHalfFromZero
  {-# INLINABLE roundDecimal #-}

roundHalfFromZero :: forall r n k p . (Integral p, KnownNat k) => Decimal r (n + k) p -> Decimal r n p
roundHalfFromZero :: Decimal r (n + k) p -> Decimal r n p
roundHalfFromZero (Decimal p
x)
    | Int
k Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0                      = p -> Decimal r n p
forall r (s :: Nat) p. p -> Decimal r s p
Decimal p
x
    | p
r p -> p -> Bool
forall a. Ord a => a -> a -> Bool
>= p
s1                     = p -> Decimal r n p
forall r (s :: Nat) p. p -> Decimal r s p
Decimal (p
q p -> p -> p
forall a. Num a => a -> a -> a
+ p
1)
    | p -> p
forall a. Num a => a -> a
signum p
r p -> p -> Bool
forall a. Ord a => a -> a -> Bool
< p
0 Bool -> Bool -> Bool
&& p -> p
forall a. Num a => a -> a
abs p
r p -> p -> Bool
forall a. Ord a => a -> a -> Bool
>= p
s1 = p -> Decimal r n p
forall r (s :: Nat) p. p -> Decimal r s p
Decimal (p
q p -> p -> p
forall a. Num a => a -> a -> a
- p
1)
    | Bool
otherwise                   = p -> Decimal r n p
forall r (s :: Nat) p. p -> Decimal r s p
Decimal p
q
    where
      k :: Int
k = Integer -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Proxy k -> Integer
forall (n :: Nat) (proxy :: Nat -> *).
KnownNat n =>
proxy n -> Integer
natVal (Proxy k
forall k (t :: k). Proxy t
Proxy :: Proxy k)) :: Int
      s1 :: p
s1 = p
10 p -> Int -> p
forall a b. (Num a, Integral b) => a -> b -> a
^ Int
k
      (p
q, p
r) = (p
2 p -> p -> p
forall a. Num a => a -> a -> a
*) (p -> p) -> (p, p) -> (p, p)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> p -> p -> (p, p)
forall a. Integral a => a -> a -> (a, a)
quotRem p
x p
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:
--
-- >>> :set -XDataKinds
-- >>> :set -XTypeApplications
-- >>> arithRoundD @1 @RoundDown @2 @Int 3.65
-- Arith 3.6
-- >>> arithRoundD @1 @RoundDown @2 @Int 3.75
-- Arith 3.7
-- >>> arithRoundD @1 @RoundDown @2 @Int 3.89
-- Arith 3.8
-- >>> arithRoundD @1 @RoundDown @2 @Int (-3.65)
-- Arith -3.7
--
-- @since 0.2.0
data RoundDown

-- | Synonym for round down
--
-- @since 0.2.0
type Floor = RoundDown

instance Round RoundDown Integer where
  roundDecimal :: Decimal RoundDown (n + k) Integer -> Decimal RoundDown n Integer
roundDecimal = Decimal RoundDown (n + k) Integer -> Decimal RoundDown n Integer
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundDown
instance Round RoundDown Int where
  roundDecimal :: Decimal RoundDown (n + k) Int -> Decimal RoundDown n Int
roundDecimal = Decimal RoundDown (n + k) Int -> Decimal RoundDown n Int
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundDown
  {-# INLINABLE roundDecimal #-}
instance Round RoundDown Int8 where
  roundDecimal :: Decimal RoundDown (n + k) Int8 -> Decimal RoundDown n Int8
roundDecimal = Decimal RoundDown (n + k) Int8 -> Decimal RoundDown n Int8
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundDown
  {-# INLINABLE roundDecimal #-}
instance Round RoundDown Int16 where
  roundDecimal :: Decimal RoundDown (n + k) Int16 -> Decimal RoundDown n Int16
roundDecimal = Decimal RoundDown (n + k) Int16 -> Decimal RoundDown n Int16
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundDown
  {-# INLINABLE roundDecimal #-}
instance Round RoundDown Int32 where
  roundDecimal :: Decimal RoundDown (n + k) Int32 -> Decimal RoundDown n Int32
roundDecimal = Decimal RoundDown (n + k) Int32 -> Decimal RoundDown n Int32
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundDown
  {-# INLINABLE roundDecimal #-}
instance Round RoundDown Int64 where
  roundDecimal :: Decimal RoundDown (n + k) Int64 -> Decimal RoundDown n Int64
roundDecimal = Decimal RoundDown (n + k) Int64 -> Decimal RoundDown n Int64
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundDown
  {-# INLINABLE roundDecimal #-}
instance Round RoundDown Word where
  roundDecimal :: Decimal RoundDown (n + k) Word -> Decimal RoundDown n Word
roundDecimal = Decimal RoundDown (n + k) Word -> Decimal RoundDown n Word
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundDown
  {-# INLINABLE roundDecimal #-}
instance Round RoundDown Word8 where
  roundDecimal :: Decimal RoundDown (n + k) Word8 -> Decimal RoundDown n Word8
roundDecimal = Decimal RoundDown (n + k) Word8 -> Decimal RoundDown n Word8
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundDown
  {-# INLINABLE roundDecimal #-}
instance Round RoundDown Word16 where
  roundDecimal :: Decimal RoundDown (n + k) Word16 -> Decimal RoundDown n Word16
roundDecimal = Decimal RoundDown (n + k) Word16 -> Decimal RoundDown n Word16
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundDown
  {-# INLINABLE roundDecimal #-}
instance Round RoundDown Word32 where
  roundDecimal :: Decimal RoundDown (n + k) Word32 -> Decimal RoundDown n Word32
roundDecimal = Decimal RoundDown (n + k) Word32 -> Decimal RoundDown n Word32
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundDown
  {-# INLINABLE roundDecimal #-}
instance Round RoundDown Word64 where
  roundDecimal :: Decimal RoundDown (n + k) Word64 -> Decimal RoundDown n Word64
roundDecimal = Decimal RoundDown (n + k) Word64 -> Decimal RoundDown n Word64
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundDown
  {-# INLINABLE roundDecimal #-}

roundDown :: forall r n k p . (Integral p, KnownNat k) => Decimal r (n + k) p -> Decimal r n p
roundDown :: Decimal r (n + k) p -> Decimal r n p
roundDown (Decimal p
x)
  | p
x p -> p -> Bool
forall a. Ord a => a -> a -> Bool
>= p
0 Bool -> Bool -> Bool
|| p
r p -> p -> Bool
forall a. Eq a => a -> a -> Bool
== p
0 = p -> Decimal r n p
forall r (s :: Nat) p. p -> Decimal r s p
Decimal p
q
  | Bool
otherwise = p -> Decimal r n p
forall r (s :: Nat) p. p -> Decimal r s p
Decimal (p
q p -> p -> p
forall a. Num a => a -> a -> a
- p
1)
  where
    k :: Int
k = Integer -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Proxy k -> Integer
forall (n :: Nat) (proxy :: Nat -> *).
KnownNat n =>
proxy n -> Integer
natVal (Proxy k
forall k (t :: k). Proxy t
Proxy :: Proxy k)) :: Int
    (p
q, p
r) = p -> p -> (p, p)
forall a. Integral a => a -> a -> (a, a)
quotRem p
x (p
10 p -> Int -> p
forall a b. (Num a, Integral b) => a -> b -> a
^ Int
k)
{-# INLINABLE roundDown #-}

-- | [Round towards zero](https://en.wikipedia.org/wiki/Rounding#Round_towards_zero)
-- strategy. Similar to Haskell's `truncate`. Drop the fractional digits, regardless of
-- the sign.
--
-- >>> :set -XDataKinds
-- >>> :set -XTypeApplications
-- >>> arithRoundD @1 @RoundToZero @2 @Int 3.65
-- Arith 3.6
-- >>> arithRoundD @1 @RoundToZero @2 @Int 3.75
-- Arith 3.7
-- >>> arithRoundD @1 @RoundToZero @2 @Int 3.89
-- Arith 3.8
-- >>> arithRoundD @1 @RoundToZero @2 @Int (-3.65)
-- Arith -3.6
--
-- @since 0.2.0
data RoundToZero


-- | Synonym for `RoundToZero`
--
-- @since 0.1.0
type Truncate = RoundToZero

instance Round RoundToZero Integer where
  roundDecimal :: Decimal RoundToZero (n + k) Integer
-> Decimal RoundToZero n Integer
roundDecimal = Decimal RoundToZero (n + k) Integer
-> Decimal RoundToZero n Integer
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundToZero
instance Round RoundToZero Int where
  roundDecimal :: Decimal RoundToZero (n + k) Int -> Decimal RoundToZero n Int
roundDecimal = Decimal RoundToZero (n + k) Int -> Decimal RoundToZero n Int
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundToZero
  {-# INLINABLE roundDecimal #-}
instance Round RoundToZero Int8 where
  roundDecimal :: Decimal RoundToZero (n + k) Int8 -> Decimal RoundToZero n Int8
roundDecimal = Decimal RoundToZero (n + k) Int8 -> Decimal RoundToZero n Int8
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundToZero
  {-# INLINABLE roundDecimal #-}
instance Round RoundToZero Int16 where
  roundDecimal :: Decimal RoundToZero (n + k) Int16 -> Decimal RoundToZero n Int16
roundDecimal = Decimal RoundToZero (n + k) Int16 -> Decimal RoundToZero n Int16
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundToZero
  {-# INLINABLE roundDecimal #-}
instance Round RoundToZero Int32 where
  roundDecimal :: Decimal RoundToZero (n + k) Int32 -> Decimal RoundToZero n Int32
roundDecimal = Decimal RoundToZero (n + k) Int32 -> Decimal RoundToZero n Int32
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundToZero
  {-# INLINABLE roundDecimal #-}
instance Round RoundToZero Int64 where
  roundDecimal :: Decimal RoundToZero (n + k) Int64 -> Decimal RoundToZero n Int64
roundDecimal = Decimal RoundToZero (n + k) Int64 -> Decimal RoundToZero n Int64
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundToZero
  {-# INLINABLE roundDecimal #-}
instance Round RoundToZero Word where
  roundDecimal :: Decimal RoundToZero (n + k) Word -> Decimal RoundToZero n Word
roundDecimal = Decimal RoundToZero (n + k) Word -> Decimal RoundToZero n Word
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundToZero
  {-# INLINABLE roundDecimal #-}
instance Round RoundToZero Word8 where
  roundDecimal :: Decimal RoundToZero (n + k) Word8 -> Decimal RoundToZero n Word8
roundDecimal = Decimal RoundToZero (n + k) Word8 -> Decimal RoundToZero n Word8
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundToZero
  {-# INLINABLE roundDecimal #-}
instance Round RoundToZero Word16 where
  roundDecimal :: Decimal RoundToZero (n + k) Word16 -> Decimal RoundToZero n Word16
roundDecimal = Decimal RoundToZero (n + k) Word16 -> Decimal RoundToZero n Word16
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundToZero
  {-# INLINABLE roundDecimal #-}
instance Round RoundToZero Word32 where
  roundDecimal :: Decimal RoundToZero (n + k) Word32 -> Decimal RoundToZero n Word32
roundDecimal = Decimal RoundToZero (n + k) Word32 -> Decimal RoundToZero n Word32
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundToZero
  {-# INLINABLE roundDecimal #-}
instance Round RoundToZero Word64 where
  roundDecimal :: Decimal RoundToZero (n + k) Word64 -> Decimal RoundToZero n Word64
roundDecimal = Decimal RoundToZero (n + k) Word64 -> Decimal RoundToZero n Word64
forall r (n :: Nat) (k :: Nat) p.
(Integral p, KnownNat k) =>
Decimal r (n + k) p -> Decimal r n p
roundToZero
  {-# INLINABLE roundDecimal #-}

roundToZero :: forall r n k p . (Integral p, KnownNat k) => Decimal r (n + k) p -> Decimal r n p
roundToZero :: Decimal r (n + k) p -> Decimal r n p
roundToZero (Decimal p
x) = p -> Decimal r n p
forall r (s :: Nat) p. p -> Decimal r s p
Decimal (p -> p -> p
forall a. Integral a => a -> a -> a
quot p
x (p
10 p -> Int -> p
forall a b. (Num a, Integral b) => a -> b -> a
^ Int
k))
  where
    k :: Int
k = Integer -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Proxy k -> Integer
forall (n :: Nat) (proxy :: Nat -> *).
KnownNat n =>
proxy n -> Integer
natVal (Proxy k
forall k (t :: k). Proxy t
Proxy :: Proxy k)) :: Int
{-# INLINABLE roundToZero #-}

-- | /O(1)/ - Conversion of a list.
--
-- __Note__: It doesn't do any scaling, eg:
--
-- >>> :set -XDataKinds
-- >>> import Numeric.Decimal
-- >>> decimalList [1,20,300] :: [Decimal RoundHalfUp 2 Int]
-- [0.01,0.20,3.00]
--
-- If scaling is what you need use `fromIntegral` instead:
--
-- >>> sequenceA [1, 20, 300] :: Arith [Decimal RoundHalfUp 2 Int]
-- Arith [1.00,20.00,300.00]
--
-- @since 0.1.0
decimalList :: Integral p => [p] -> [Decimal r s p]
decimalList :: [p] -> [Decimal r s p]
decimalList = [p] -> [Decimal r s p]
coerce


-- | Sum a list of decimal numbers
--
-- >>> :set -XDataKinds
-- >>> sequenceA [1.1, 20.02, 300.003] >>= sumDecimalBounded :: Arith (Decimal RoundHalfUp 3 Int)
-- Arith 321.123
--
-- @since 0.2.0
sumDecimalBounded ::
     (MonadThrow m, Foldable f, Eq p, Ord p, Num p, Bounded p)
  => f (Decimal r s p)
  -> m (Decimal r s p)
sumDecimalBounded :: f (Decimal r s p) -> m (Decimal r s p)
sumDecimalBounded = (Decimal r s p -> Decimal r s p -> m (Decimal r s p))
-> Decimal r s p -> f (Decimal r s p) -> m (Decimal r s p)
forall (t :: * -> *) (m :: * -> *) b a.
(Foldable t, Monad m) =>
(b -> a -> m b) -> b -> t a -> m b
foldM Decimal r s p -> Decimal r s p -> m (Decimal r s p)
forall (m :: * -> *) p r (s :: Nat).
(MonadThrow m, Eq p, Ord p, Num p, Bounded p) =>
Decimal r s p -> Decimal r s p -> m (Decimal r s p)
plusDecimalBounded (p -> Decimal r s p
forall r (s :: Nat) p. p -> Decimal r s p
Decimal p
0)
{-# INLINABLE sumDecimalBounded #-}

-- | Multiply all decimal numbers in the list while doing rounding.
--
-- >>> :set -XDataKinds
-- >>> product [1.1, 20.02, 300.003] :: Double
-- 6606.666066000001
-- >>> xs <- arithM (mapM fromRational [1.1, 20.02, 300.003] :: Arith [Decimal RoundHalfUp 4 Int])
-- >>> xs
-- [1.1000,20.0200,300.0030]
-- >>> productDecimalBoundedWithRounding xs
-- 6606.6661
--
-- @since 0.2.0
productDecimalBoundedWithRounding ::
     (MonadThrow m, Foldable f, KnownNat s, Round r Integer, Integral p, Bounded p)
  => f (Decimal r s p)
  -> m (Decimal r s p)
productDecimalBoundedWithRounding :: f (Decimal r s p) -> m (Decimal r s p)
productDecimalBoundedWithRounding f (Decimal r s p)
ds =
  p -> m (Decimal r s p)
forall p (s :: Nat) (m :: * -> *) r.
(Integral p, Bounded p, KnownNat s, MonadThrow m) =>
p -> m (Decimal r s p)
fromIntegralDecimalBounded p
1 m (Decimal r s p)
-> (Decimal r s p -> m (Decimal r s p)) -> m (Decimal r s p)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=
  (\Decimal r s p
acc -> (Decimal r s p -> Decimal r s p -> m (Decimal r s p))
-> Decimal r s p -> f (Decimal r s p) -> m (Decimal r s p)
forall (t :: * -> *) (m :: * -> *) b a.
(Foldable t, Monad m) =>
(b -> a -> m b) -> b -> t a -> m b
foldM Decimal r s p -> Decimal r s p -> m (Decimal r s p)
forall (m :: * -> *) (s :: Nat) r p.
(MonadThrow m, KnownNat s, Round r Integer, Integral p,
 Bounded p) =>
Decimal r s p -> Decimal r s p -> m (Decimal r s p)
timesDecimalBoundedWithRounding Decimal r s p
acc f (Decimal r s p)
ds)
{-# INLINABLE productDecimalBoundedWithRounding #-}


---- Scientific


-- | Convert a `Decimal` to `Scientific`
--
-- @since 0.1.0
toScientificDecimal :: (Integral p, KnownNat s) => Decimal r s p -> Scientific
toScientificDecimal :: Decimal r s p -> Scientific
toScientificDecimal Decimal r s p
dec =
  Integer -> Int -> Scientific
scientific
    (p -> Integer
forall a. Integral a => a -> Integer
toInteger (Decimal r s p -> p
forall r (s :: Nat) p. Decimal r s p -> p
unwrapDecimal Decimal r s p
dec))
    (Integer -> Int
forall a. Num a => Integer -> a
fromInteger (Integer -> Integer
forall a. Num a => a -> a
negate (Decimal r s p -> Integer
forall r (s :: Nat) p. KnownNat s => Decimal r s p -> Integer
getScale Decimal r s p
dec)))

-- | Convert Scientific to Decimal without loss of precision. Will return `Left` `Underflow` if
-- `Scientific` has too many decimal places, more than `Decimal` scaling is capable to handle.
--
-- @since 0.1.0
fromScientificDecimal ::
     forall m r s. (MonadThrow m, KnownNat s)
  => Scientific
  -> m (Decimal r s Integer)
fromScientificDecimal :: Scientific -> m (Decimal r s Integer)
fromScientificDecimal Scientific
numNonNormal
  | Integer
exp10 Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
> Integer
s = ArithException -> m (Decimal r s Integer)
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM ArithException
Underflow
  | Bool
otherwise = Decimal r s Integer -> m (Decimal r s Integer)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Integer -> Decimal r s Integer
forall r (s :: Nat) p. p -> Decimal r s p
Decimal (Scientific -> Integer
coefficient Scientific
num Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
10 Integer -> Integer -> Integer
forall a b. (Num a, Integral b) => a -> b -> a
^ (Integer
s Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
- Integer
exp10)))
  where
    num :: Scientific
num = Scientific -> Scientific
normalize Scientific
numNonNormal
    s :: Integer
s = Proxy s -> Integer
forall (n :: Nat) (proxy :: Nat -> *).
KnownNat n =>
proxy n -> Integer
natVal (Proxy s
forall k (t :: k). Proxy t
Proxy :: Proxy s)
    exp10 :: Integer
exp10 = Integer -> Integer
forall a. Num a => a -> a
negate (Int -> Integer
forall a. Integral a => a -> Integer
toInteger (Scientific -> Int
base10Exponent Scientific
num))

-- | 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 :: Scientific -> m (Decimal r s p)
fromScientificDecimalBounded Scientific
numNonNormal = do
  Bool -> m () -> m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Integer
coeff Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
< p -> Integer
forall a. Integral a => a -> Integer
toInteger (p
forall a. Bounded a => a
minBound :: p) Bool -> Bool -> Bool
|| Integer
exp10 Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
> Integer
s) (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$ ArithException -> m ()
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM ArithException
Underflow
  Bool -> m () -> m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Integer
coeff Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
> Integer
imax Bool -> Bool -> Bool
|| Integer
posExp10 Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
> Integer
upperExponentBound Bool -> Bool -> Bool
|| Integer
scaledCoeff Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
> Integer
imax) (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$ ArithException -> m ()
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM ArithException
Overflow
  Decimal r s p -> m (Decimal r s p)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (p -> Decimal r s p
forall r (s :: Nat) p. p -> Decimal r s p
Decimal (Integer -> p
forall a. Num a => Integer -> a
fromInteger Integer
scaledCoeff))
  where
    num :: Scientific
num = Scientific -> Scientific
normalize Scientific
numNonNormal
    s :: Integer
s = Proxy s -> Integer
forall (n :: Nat) (proxy :: Nat -> *).
KnownNat n =>
proxy n -> Integer
natVal (Proxy s
forall k (t :: k). Proxy t
Proxy :: Proxy s)
    posExp10 :: Integer
posExp10 = Int -> Integer
forall a. Integral a => a -> Integer
toInteger (Scientific -> Int
base10Exponent Scientific
num)
    exp10 :: Integer
exp10 = Integer -> Integer
forall a. Num a => a -> a
negate Integer
posExp10
    imax :: Integer
imax = p -> Integer
forall a. Integral a => a -> Integer
toInteger (p
forall a. Bounded a => a
maxBound :: p)
    coeff :: Integer
coeff = Scientific -> Integer
coefficient Scientific
num
    scaledCoeff :: Integer
scaledCoeff = Scientific -> Integer
coefficient Scientific
num Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
10 Integer -> Integer -> Integer
forall a b. (Num a, Integral b) => a -> b -> a
^ (Integer
s Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
- Integer
exp10)
    upperExponentBound :: Integer
upperExponentBound = Double -> Integer
forall a b. (RealFrac a, Integral b) => a -> b
ceiling (Double -> Double -> Double
forall a. Floating a => a -> a -> a
logBase Double
10 (Double -> Double) -> Double -> Double
forall a b. (a -> b) -> a -> b
$ p -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral (p
forall a. Bounded a => a
maxBound :: p) :: Double) Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
- Integer
s


type family FixedScale e :: Nat

type instance FixedScale E0 = 0
type instance FixedScale E1 = 1
type instance FixedScale E2 = 2
type instance FixedScale E3 = 3
type instance FixedScale E6 = 6
type instance FixedScale E9 = 9
type instance FixedScale E12 = 12


-- | Convert a `Decimal` to a `Fixed` with the exactly same precision.
--
-- >>> toFixedDecimal <$> (3.65 :: Arith (Decimal RoundDown 2 Int)) :: Arith (Fixed E2)
-- Arith 3.65
-- >>> toFixedDecimal $ fromFixedDecimal (123.45 :: Fixed E2) :: Fixed E2
-- 123.45
--
-- @since 0.2.0
toFixedDecimal :: (s ~ FixedScale e, Integral p) => Decimal r s p -> Fixed e
toFixedDecimal :: Decimal r s p -> Fixed e
toFixedDecimal = Integer -> Fixed e
forall k (a :: k). Integer -> Fixed a
MkFixed (Integer -> Fixed e)
-> (Decimal r s p -> Integer) -> Decimal r s p -> Fixed e
forall b c a. (b -> c) -> (a -> b) -> a -> c
. p -> Integer
forall a. Integral a => a -> Integer
toInteger (p -> Integer) -> (Decimal r s p -> p) -> Decimal r s p -> Integer
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Decimal r s p -> p
forall r (s :: Nat) p. Decimal r s p -> p
unwrapDecimal

-- | Convert a `Fixed` to a `Decimal` with the exactly same precision
--
-- >>> fromFixedDecimal (123.45 :: Fixed E2)
-- 123.45
--
-- @since 0.2.0
fromFixedDecimal :: s ~ FixedScale e => Fixed e -> Decimal r s Integer
fromFixedDecimal :: Fixed e -> Decimal r s Integer
fromFixedDecimal = Fixed e -> Decimal r s Integer
coerce

-- | Convert a `Fixed` to a decimal backed by a bounded integral with the exactly same
-- precision
--
-- >>> fromFixedDecimalBounded (123.458 :: Fixed E3) :: Arith (Decimal RoundToZero 3 Int)
-- Arith 123.458
-- >>> fromFixedDecimalBounded (123.458 :: Fixed E3) :: Arith (Decimal RoundToZero 3 Int8)
-- ArithError arithmetic overflow
-- >>> fromFixedDecimalBounded (-123.458 :: Fixed E3) :: Arith (Decimal RoundToZero 3 Word)
-- ArithError arithmetic underflow
--
-- @since 0.2.0
fromFixedDecimalBounded ::
     (s ~ FixedScale e, MonadThrow m, Integral p, Bounded p)
  => Fixed e
  -> m (Decimal r s p)
fromFixedDecimalBounded :: Fixed e -> m (Decimal r s p)
fromFixedDecimalBounded = Decimal r s Integer -> m (Decimal r s p)
forall (m :: * -> *) r (s :: Nat) p.
(MonadThrow m, Integral p, Bounded p) =>
Decimal r s Integer -> m (Decimal r s p)
fromIntegerDecimalBounded (Decimal r s Integer -> m (Decimal r s p))
-> (Fixed e -> Decimal r s Integer) -> Fixed e -> m (Decimal r s p)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Fixed e -> Decimal r s Integer
forall (s :: Nat) e r.
(s ~ FixedScale e) =>
Fixed e -> Decimal r s Integer
fromFixedDecimal