{-# LANGUAGE DeriveDataTypeable #-}
module Data.Decimal (
DecimalRaw (..),
Decimal,
realFracToDecimal,
decimalConvert,
unsafeDecimalConvert,
roundTo,
roundTo',
(*.),
divide,
allocate,
eitherFromRational,
normalizeDecimal
) where
import Control.DeepSeq
import Data.Char
import Data.Ratio
import Data.Word
import Data.Typeable
import Text.ParserCombinators.ReadP
data DecimalRaw i = Decimal {
DecimalRaw i -> Word8
decimalPlaces :: ! Word8,
DecimalRaw i -> i
decimalMantissa :: ! i}
deriving (Typeable)
type Decimal = DecimalRaw Integer
instance (NFData i) => NFData (DecimalRaw i) where
rnf :: DecimalRaw i -> ()
rnf (Decimal _ i :: i
i) = i -> ()
forall a. NFData a => a -> ()
rnf i
i
instance (Integral i) => Enum (DecimalRaw i) where
succ :: DecimalRaw i -> DecimalRaw i
succ x :: DecimalRaw i
x = DecimalRaw i
x DecimalRaw i -> DecimalRaw i -> DecimalRaw i
forall a. Num a => a -> a -> a
+ 1
pred :: DecimalRaw i -> DecimalRaw i
pred x :: DecimalRaw i
x = DecimalRaw i
x DecimalRaw i -> DecimalRaw i -> DecimalRaw i
forall a. Num a => a -> a -> a
- 1
toEnum :: Int -> DecimalRaw i
toEnum = Int -> DecimalRaw i
forall a b. (Integral a, Num b) => a -> b
fromIntegral
fromEnum :: DecimalRaw i -> Int
fromEnum = i -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (i -> Int) -> (DecimalRaw i -> i) -> DecimalRaw i -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. DecimalRaw i -> i
forall i. DecimalRaw i -> i
decimalMantissa (DecimalRaw i -> i)
-> (DecimalRaw i -> DecimalRaw i) -> DecimalRaw i -> i
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word8 -> DecimalRaw i -> DecimalRaw i
forall i. Integral i => Word8 -> DecimalRaw i -> DecimalRaw i
roundTo 0
enumFrom :: DecimalRaw i -> [DecimalRaw i]
enumFrom = (DecimalRaw i -> DecimalRaw i) -> DecimalRaw i -> [DecimalRaw i]
forall a. (a -> a) -> a -> [a]
iterate (DecimalRaw i -> DecimalRaw i -> DecimalRaw i
forall a. Num a => a -> a -> a
+1)
enumFromThen :: DecimalRaw i -> DecimalRaw i -> [DecimalRaw i]
enumFromThen x1 :: DecimalRaw i
x1 x2 :: DecimalRaw i
x2 = let dx :: DecimalRaw i
dx = DecimalRaw i
x2 DecimalRaw i -> DecimalRaw i -> DecimalRaw i
forall a. Num a => a -> a -> a
- DecimalRaw i
x1 in (DecimalRaw i -> DecimalRaw i) -> DecimalRaw i -> [DecimalRaw i]
forall a. (a -> a) -> a -> [a]
iterate (DecimalRaw i -> DecimalRaw i -> DecimalRaw i
forall a. Num a => a -> a -> a
+DecimalRaw i
dx) DecimalRaw i
x1
enumFromTo :: DecimalRaw i -> DecimalRaw i -> [DecimalRaw i]
enumFromTo x1 :: DecimalRaw i
x1 x2 :: DecimalRaw i
x2 = (DecimalRaw i -> Bool) -> [DecimalRaw i] -> [DecimalRaw i]
forall a. (a -> Bool) -> [a] -> [a]
takeWhile (DecimalRaw i -> DecimalRaw i -> Bool
forall a. Ord a => a -> a -> Bool
<= DecimalRaw i
x2) ([DecimalRaw i] -> [DecimalRaw i])
-> [DecimalRaw i] -> [DecimalRaw i]
forall a b. (a -> b) -> a -> b
$ (DecimalRaw i -> DecimalRaw i) -> DecimalRaw i -> [DecimalRaw i]
forall a. (a -> a) -> a -> [a]
iterate (DecimalRaw i -> DecimalRaw i -> DecimalRaw i
forall a. Num a => a -> a -> a
+1) DecimalRaw i
x1
enumFromThenTo :: DecimalRaw i -> DecimalRaw i -> DecimalRaw i -> [DecimalRaw i]
enumFromThenTo x1 :: DecimalRaw i
x1 x2 :: DecimalRaw i
x2 x3 :: DecimalRaw i
x3 = (DecimalRaw i -> Bool) -> [DecimalRaw i] -> [DecimalRaw i]
forall a. (a -> Bool) -> [a] -> [a]
takeWhile (DecimalRaw i -> DecimalRaw i -> Bool
forall a. Ord a => a -> a -> Bool
<= DecimalRaw i
x3) ([DecimalRaw i] -> [DecimalRaw i])
-> [DecimalRaw i] -> [DecimalRaw i]
forall a b. (a -> b) -> a -> b
$ DecimalRaw i -> DecimalRaw i -> [DecimalRaw i]
forall a. Enum a => a -> a -> [a]
enumFromThen DecimalRaw i
x1 DecimalRaw i
x2
realFracToDecimal :: (Integral i, RealFrac r) => Word8 -> r -> DecimalRaw i
realFracToDecimal :: Word8 -> r -> DecimalRaw i
realFracToDecimal e :: Word8
e r :: r
r = Word8 -> i -> DecimalRaw i
forall i. Word8 -> i -> DecimalRaw i
Decimal Word8
e (i -> DecimalRaw i) -> i -> DecimalRaw i
forall a b. (a -> b) -> a -> b
$ r -> i
forall a b. (RealFrac a, Integral b) => a -> b
round (r
r r -> r -> r
forall a. Num a => a -> a -> a
* (10r -> Word8 -> r
forall a b. (Num a, Integral b) => a -> b -> a
^Word8
e))
divRound :: (Integral a) => a -> a -> a
divRound :: a -> a -> a
divRound n1 :: a
n1 n2 :: a
n2 = a
n a -> a -> a
forall a. Num a => a -> a -> a
+ a
bankers
where
(n :: a
n, r :: a
r) = a
n1 a -> a -> (a, a)
forall a. Integral a => a -> a -> (a, a)
`quotRem` a
n2
bankers :: a
bankers = case a -> a -> Ordering
forall a. Ord a => a -> a -> Ordering
compare (a -> a
forall a. Num a => a -> a
abs a
r a -> a -> a
forall a. Num a => a -> a -> a
* 2) (a -> a
forall a. Num a => a -> a
abs a
n2) of
LT -> 0
GT -> a -> a
forall a. Num a => a -> a
signum a
n1
EQ -> if a -> Bool
forall a. Integral a => a -> Bool
odd a
n then a -> a
forall a. Num a => a -> a
signum a
n1 else 0
unsafeDecimalConvert :: (Integral a, Integral b) => DecimalRaw a -> DecimalRaw b
unsafeDecimalConvert :: DecimalRaw a -> DecimalRaw b
unsafeDecimalConvert (Decimal e :: Word8
e n :: a
n) = Word8 -> b -> DecimalRaw b
forall i. Word8 -> i -> DecimalRaw i
Decimal Word8
e (b -> DecimalRaw b) -> b -> DecimalRaw b
forall a b. (a -> b) -> a -> b
$ a -> b
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
n
decimalConvert :: (Integral a, Integral b, Bounded b) =>
DecimalRaw a -> Maybe (DecimalRaw b)
decimalConvert :: DecimalRaw a -> Maybe (DecimalRaw b)
decimalConvert (Decimal e :: Word8
e n :: a
n) =
let n1 :: Integer
n1 :: Integer
n1 = a -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
n
n2 :: b
n2 = a -> b
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
n
ub :: Integer
ub = b -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral (b -> Integer) -> b -> Integer
forall a b. (a -> b) -> a -> b
$ b -> b -> b
forall a. Ord a => a -> a -> a
max b
forall a. Bounded a => a
maxBound b
n2
lb :: Integer
lb = b -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral (b -> Integer) -> b -> Integer
forall a b. (a -> b) -> a -> b
$ b -> b -> b
forall a. Ord a => a -> a -> a
min b
forall a. Bounded a => a
minBound b
n2
in if Integer
lb Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
<= Integer
n1 Bool -> Bool -> Bool
&& Integer
n1 Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
<= Integer
ub then DecimalRaw b -> Maybe (DecimalRaw b)
forall a. a -> Maybe a
Just (DecimalRaw b -> Maybe (DecimalRaw b))
-> DecimalRaw b -> Maybe (DecimalRaw b)
forall a b. (a -> b) -> a -> b
$ Word8 -> b -> DecimalRaw b
forall i. Word8 -> i -> DecimalRaw i
Decimal Word8
e b
n2 else Maybe (DecimalRaw b)
forall a. Maybe a
Nothing
roundTo :: (Integral i) => Word8 -> DecimalRaw i -> DecimalRaw i
roundTo :: Word8 -> DecimalRaw i -> DecimalRaw i
roundTo d :: Word8
d (Decimal _ 0) = Word8 -> i -> DecimalRaw i
forall i. Word8 -> i -> DecimalRaw i
Decimal Word8
d 0
roundTo d :: Word8
d (Decimal e :: Word8
e n :: i
n) = Word8 -> i -> DecimalRaw i
forall i. Word8 -> i -> DecimalRaw i
Decimal Word8
d (i -> DecimalRaw i) -> i -> DecimalRaw i
forall a b. (a -> b) -> a -> b
$ i -> i
forall a b. (Integral a, Num b) => a -> b
fromIntegral i
n1
where
n1 :: i
n1 = case Word8 -> Word8 -> Ordering
forall a. Ord a => a -> a -> Ordering
compare Word8
d Word8
e of
LT -> i
n i -> i -> i
forall a. Integral a => a -> a -> a
`divRound` i
divisor
EQ -> i
n
GT -> i
n i -> i -> i
forall a. Num a => a -> a -> a
* i
multiplier
divisor :: i
divisor = 10 i -> Word8 -> i
forall a b. (Num a, Integral b) => a -> b -> a
^ (Word8
eWord8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
-Word8
d)
multiplier :: i
multiplier = 10 i -> Word8 -> i
forall a b. (Num a, Integral b) => a -> b -> a
^ (Word8
dWord8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
-Word8
e)
roundTo' :: (Integral i) => (Rational -> i) -> Word8 -> DecimalRaw i -> DecimalRaw i
roundTo' :: (Rational -> i) -> Word8 -> DecimalRaw i -> DecimalRaw i
roundTo' _ d :: Word8
d (Decimal _ 0) = Word8 -> i -> DecimalRaw i
forall i. Word8 -> i -> DecimalRaw i
Decimal Word8
d 0
roundTo' f :: Rational -> i
f d :: Word8
d (Decimal e :: Word8
e n :: i
n) = Word8 -> i -> DecimalRaw i
forall i. Word8 -> i -> DecimalRaw i
Decimal Word8
d (i -> DecimalRaw i) -> i -> DecimalRaw i
forall a b. (a -> b) -> a -> b
$ Rational -> i
f Rational
n1
where
divisor :: Rational
divisor = 10 Rational -> Word8 -> Rational
forall a b. (Num a, Integral b) => a -> b -> a
^ (Word8
eWord8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
-Word8
d)
multiplier :: Rational
multiplier = 10 Rational -> Word8 -> Rational
forall a b. (Num a, Integral b) => a -> b -> a
^ (Word8
dWord8 -> Word8 -> Word8
forall a. Num a => a -> a -> a
-Word8
e)
n1 :: Rational
n1 = case Word8 -> Word8 -> Ordering
forall a. Ord a => a -> a -> Ordering
compare Word8
d Word8
e of
LT -> i -> Rational
forall a. Real a => a -> Rational
toRational i
n Rational -> Rational -> Rational
forall a. Fractional a => a -> a -> a
/ Rational
divisor
EQ -> i -> Rational
forall a. Real a => a -> Rational
toRational i
n
GT -> i -> Rational
forall a. Real a => a -> Rational
toRational i
n Rational -> Rational -> Rational
forall a. Num a => a -> a -> a
* Rational
multiplier
roundMax :: (Integral i) => DecimalRaw i -> DecimalRaw i -> (Word8, i, i)
roundMax :: DecimalRaw i -> DecimalRaw i -> (Word8, i, i)
roundMax (Decimal _ 0) (Decimal _ 0) = (0,0,0)
roundMax (Decimal e1 :: Word8
e1 n1 :: i
n1) (Decimal _ 0) = (Word8
e1,i
n1,0)
roundMax (Decimal _ 0) (Decimal e2 :: Word8
e2 n2 :: i
n2) = (Word8
e2,0,i
n2)
roundMax d1 :: DecimalRaw i
d1@(Decimal e1 :: Word8
e1 n1 :: i
n1) d2 :: DecimalRaw i
d2@(Decimal e2 :: Word8
e2 n2 :: i
n2)
| Word8
e1 Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== Word8
e2 = (Word8
e1, i
n1, i
n2)
| Bool
otherwise = (Word8
e, i
n1', i
n2')
where
e :: Word8
e = Word8 -> Word8 -> Word8
forall a. Ord a => a -> a -> a
max Word8
e1 Word8
e2
(Decimal _ n1' :: i
n1') = Word8 -> DecimalRaw i -> DecimalRaw i
forall i. Integral i => Word8 -> DecimalRaw i -> DecimalRaw i
roundTo Word8
e DecimalRaw i
d1
(Decimal _ n2' :: i
n2') = Word8 -> DecimalRaw i -> DecimalRaw i
forall i. Integral i => Word8 -> DecimalRaw i -> DecimalRaw i
roundTo Word8
e DecimalRaw i
d2
instance (Integral i, Show i) => Show (DecimalRaw i) where
showsPrec :: Int -> DecimalRaw i -> ShowS
showsPrec _ (Decimal e :: Word8
e n :: i
n)
| Word8
e Word8 -> Word8 -> Bool
forall a. Eq a => a -> a -> Bool
== 0 = ((String
signStr String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
strN) String -> ShowS
forall a. [a] -> [a] -> [a]
++)
| Bool
otherwise = ([String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [String
signStr, String
intPart, ".", String
fracPart] String -> ShowS
forall a. [a] -> [a] -> [a]
++)
where
strN :: String
strN = i -> String
forall a. Show a => a -> String
show (i -> String) -> i -> String
forall a b. (a -> b) -> a -> b
$ i -> i
forall a. Num a => a -> a
abs i
n
signStr :: String
signStr = if i
n i -> i -> Bool
forall a. Ord a => a -> a -> Bool
< 0 then "-" else ""
len :: Int
len = String -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
strN
padded :: String
padded = Int -> Char -> String
forall a. Int -> a -> [a]
replicate (Word8 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
e Int -> Int -> Int
forall a. Num a => a -> a -> a
+ 1 Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
len) '0' String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
strN
(intPart :: String
intPart, fracPart :: String
fracPart) = Int -> String -> (String, String)
forall a. Int -> [a] -> ([a], [a])
splitAt (Int -> Int -> Int
forall a. Ord a => a -> a -> a
max 1 (Int
len Int -> Int -> Int
forall a. Num a => a -> a -> a
- Word8 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
e)) String
padded
instance (Integral i, Read i) => Read (DecimalRaw i) where
readsPrec :: Int -> ReadS (DecimalRaw i)
readsPrec _ = ReadP (DecimalRaw i) -> ReadS (DecimalRaw i)
forall a. ReadP a -> ReadS a
readP_to_S ReadP (DecimalRaw i)
forall i. (Integral i, Read i) => ReadP (DecimalRaw i)
readDecimalP
readDecimalP :: (Integral i, Read i) => ReadP (DecimalRaw i)
readDecimalP :: ReadP (DecimalRaw i)
readDecimalP = do
ReadP ()
skipSpaces
Char
s1 <- Char -> ReadP Char -> ReadP Char
forall a. a -> ReadP a -> ReadP a
myOpt '+' (ReadP Char -> ReadP Char) -> ReadP Char -> ReadP Char
forall a b. (a -> b) -> a -> b
$ Char -> ReadP Char
char '-' ReadP Char -> ReadP Char -> ReadP Char
forall a. ReadP a -> ReadP a -> ReadP a
+++ Char -> ReadP Char
char '+'
String
intPart <- (Char -> Bool) -> ReadP String
munch1 Char -> Bool
isDigit
String
fractPart <- String -> ReadP String -> ReadP String
forall a. a -> ReadP a -> ReadP a
myOpt "" (ReadP String -> ReadP String) -> ReadP String -> ReadP String
forall a b. (a -> b) -> a -> b
$ do
Char
_ <- Char -> ReadP Char
char '.'
(Char -> Bool) -> ReadP String
munch1 Char -> Bool
isDigit
Int
expPart <- Int -> ReadP Int -> ReadP Int
forall a. a -> ReadP a -> ReadP a
myOpt 0 (ReadP Int -> ReadP Int) -> ReadP Int -> ReadP Int
forall a b. (a -> b) -> a -> b
$ do
Char
_ <- Char -> ReadP Char
char 'e' ReadP Char -> ReadP Char -> ReadP Char
forall a. ReadP a -> ReadP a -> ReadP a
+++ Char -> ReadP Char
char 'E'
Char
s2 <- Char -> ReadP Char -> ReadP Char
forall a. a -> ReadP a -> ReadP a
myOpt '+' (ReadP Char -> ReadP Char) -> ReadP Char -> ReadP Char
forall a b. (a -> b) -> a -> b
$ Char -> ReadP Char
char '-' ReadP Char -> ReadP Char -> ReadP Char
forall a. ReadP a -> ReadP a -> ReadP a
+++ Char -> ReadP Char
char '+'
(String -> Int) -> ReadP String -> ReadP Int
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Char -> Int -> Int
forall p. Num p => Char -> p -> p
applySign Char
s2 (Int -> Int) -> (String -> Int) -> String -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Int
forall n. Integral n => String -> n
strToInt) (ReadP String -> ReadP Int) -> ReadP String -> ReadP Int
forall a b. (a -> b) -> a -> b
$ (Char -> Bool) -> ReadP String
munch1 Char -> Bool
isDigit
let n :: i
n = Char -> i -> i
forall p. Num p => Char -> p -> p
applySign Char
s1 (i -> i) -> i -> i
forall a b. (a -> b) -> a -> b
$ String -> i
forall n. Integral n => String -> n
strToInt (String -> i) -> String -> i
forall a b. (a -> b) -> a -> b
$ String
intPart String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
fractPart
e :: Int
e = String -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
fractPart Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
expPart
if Int
e Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< 0
then DecimalRaw i -> ReadP (DecimalRaw i)
forall (m :: * -> *) a. Monad m => a -> m a
return (DecimalRaw i -> ReadP (DecimalRaw i))
-> DecimalRaw i -> ReadP (DecimalRaw i)
forall a b. (a -> b) -> a -> b
$ Word8 -> i -> DecimalRaw i
forall i. Word8 -> i -> DecimalRaw i
Decimal 0 (i -> DecimalRaw i) -> i -> DecimalRaw i
forall a b. (a -> b) -> a -> b
$ i
n i -> i -> i
forall a. Num a => a -> a -> a
* 10 i -> Int -> i
forall a b. (Num a, Integral b) => a -> b -> a
^ Int -> Int
forall a. Num a => a -> a
negate Int
e
else if Int
e Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< 256
then DecimalRaw i -> ReadP (DecimalRaw i)
forall (m :: * -> *) a. Monad m => a -> m a
return (DecimalRaw i -> ReadP (DecimalRaw i))
-> DecimalRaw i -> ReadP (DecimalRaw i)
forall a b. (a -> b) -> a -> b
$ Word8 -> i -> DecimalRaw i
forall i. Word8 -> i -> DecimalRaw i
Decimal (Int -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
e) i
n
else ReadP (DecimalRaw i)
forall a. ReadP a
pfail
where
strToInt :: (Integral n) => String -> n
strToInt :: String -> n
strToInt = (n -> n -> n) -> n -> [n] -> n
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl (\t :: n
t v :: n
v -> 10 n -> n -> n
forall a. Num a => a -> a -> a
* n
t n -> n -> n
forall a. Num a => a -> a -> a
+ n
v) 0 ([n] -> n) -> (String -> [n]) -> String -> n
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> n) -> String -> [n]
forall a b. (a -> b) -> [a] -> [b]
map (Int -> n
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> n) -> (Char -> Int) -> Char -> n
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Int -> Int
forall a. Num a => a -> a -> a
subtract (Char -> Int
ord '0') (Int -> Int) -> (Char -> Int) -> Char -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Int
ord)
applySign :: Char -> p -> p
applySign '-' v :: p
v = p -> p
forall a. Num a => a -> a
negate p
v
applySign _ v :: p
v = p
v
myOpt :: a -> ReadP a -> ReadP a
myOpt d :: a
d p :: ReadP a
p = ReadP a
p ReadP a -> ReadP a -> ReadP a
forall a. ReadP a -> ReadP a -> ReadP a
<++ a -> ReadP a
forall (m :: * -> *) a. Monad m => a -> m a
return a
d
instance (Integral i) => Eq (DecimalRaw i) where
d1 :: DecimalRaw i
d1 == :: DecimalRaw i -> DecimalRaw i -> Bool
== d2 :: DecimalRaw i
d2 = i
n1 i -> i -> Bool
forall a. Eq a => a -> a -> Bool
== i
n2 where (_, n1 :: i
n1, n2 :: i
n2) = DecimalRaw i -> DecimalRaw i -> (Word8, i, i)
forall i.
Integral i =>
DecimalRaw i -> DecimalRaw i -> (Word8, i, i)
roundMax DecimalRaw i
d1 DecimalRaw i
d2
instance (Integral i) => Ord (DecimalRaw i) where
compare :: DecimalRaw i -> DecimalRaw i -> Ordering
compare d1 :: DecimalRaw i
d1 d2 :: DecimalRaw i
d2 = i -> i -> Ordering
forall a. Ord a => a -> a -> Ordering
compare i
n1 i
n2 where (_, n1 :: i
n1, n2 :: i
n2) = DecimalRaw i -> DecimalRaw i -> (Word8, i, i)
forall i.
Integral i =>
DecimalRaw i -> DecimalRaw i -> (Word8, i, i)
roundMax DecimalRaw i
d1 DecimalRaw i
d2
instance (Integral i) => Num (DecimalRaw i) where
(Decimal _ 0) + :: DecimalRaw i -> DecimalRaw i -> DecimalRaw i
+ d :: DecimalRaw i
d = DecimalRaw i
d
d :: DecimalRaw i
d + (Decimal _ 0) = DecimalRaw i
d
d1 :: DecimalRaw i
d1 + d2 :: DecimalRaw i
d2 = Word8 -> i -> DecimalRaw i
forall i. Word8 -> i -> DecimalRaw i
Decimal Word8
e (i -> DecimalRaw i) -> i -> DecimalRaw i
forall a b. (a -> b) -> a -> b
$ i -> i
forall a b. (Integral a, Num b) => a -> b
fromIntegral (i
n1 i -> i -> i
forall a. Num a => a -> a -> a
+ i
n2)
where (e :: Word8
e, n1 :: i
n1, n2 :: i
n2) = DecimalRaw i -> DecimalRaw i -> (Word8, i, i)
forall i.
Integral i =>
DecimalRaw i -> DecimalRaw i -> (Word8, i, i)
roundMax DecimalRaw i
d1 DecimalRaw i
d2
(Decimal _ 0) - :: DecimalRaw i -> DecimalRaw i -> DecimalRaw i
- (Decimal e :: Word8
e n :: i
n) = Word8 -> i -> DecimalRaw i
forall i. Word8 -> i -> DecimalRaw i
Decimal Word8
e (-i
n)
d :: DecimalRaw i
d - (Decimal _ 0) = DecimalRaw i
d
d1 :: DecimalRaw i
d1 - d2 :: DecimalRaw i
d2 = Word8 -> i -> DecimalRaw i
forall i. Word8 -> i -> DecimalRaw i
Decimal Word8
e (i -> DecimalRaw i) -> i -> DecimalRaw i
forall a b. (a -> b) -> a -> b
$ i -> i
forall a b. (Integral a, Num b) => a -> b
fromIntegral (i
n1 i -> i -> i
forall a. Num a => a -> a -> a
- i
n2)
where (e :: Word8
e, n1 :: i
n1, n2 :: i
n2) = DecimalRaw i -> DecimalRaw i -> (Word8, i, i)
forall i.
Integral i =>
DecimalRaw i -> DecimalRaw i -> (Word8, i, i)
roundMax DecimalRaw i
d1 DecimalRaw i
d2
(Decimal _ 0) * :: DecimalRaw i -> DecimalRaw i -> DecimalRaw i
* _ = 0
_ * (Decimal _ 0) = 0
d1 :: DecimalRaw i
d1 * d2 :: DecimalRaw i
d2 = DecimalRaw i -> DecimalRaw i
forall i. Integral i => DecimalRaw i -> DecimalRaw i
normalizeDecimal (DecimalRaw i -> DecimalRaw i) -> DecimalRaw i -> DecimalRaw i
forall a b. (a -> b) -> a -> b
$ Word8 -> Rational -> DecimalRaw i
forall i r. (Integral i, RealFrac r) => Word8 -> r -> DecimalRaw i
realFracToDecimal Word8
forall a. Bounded a => a
maxBound (Rational -> DecimalRaw i) -> Rational -> DecimalRaw i
forall a b. (a -> b) -> a -> b
$ DecimalRaw i -> Rational
forall a. Real a => a -> Rational
toRational DecimalRaw i
d1 Rational -> Rational -> Rational
forall a. Num a => a -> a -> a
* DecimalRaw i -> Rational
forall a. Real a => a -> Rational
toRational DecimalRaw i
d2
abs :: DecimalRaw i -> DecimalRaw i
abs (Decimal e :: Word8
e n :: i
n) = Word8 -> i -> DecimalRaw i
forall i. Word8 -> i -> DecimalRaw i
Decimal Word8
e (i -> DecimalRaw i) -> i -> DecimalRaw i
forall a b. (a -> b) -> a -> b
$ i -> i
forall a. Num a => a -> a
abs i
n
signum :: DecimalRaw i -> DecimalRaw i
signum (Decimal _ n :: i
n) = i -> DecimalRaw i
forall a b. (Integral a, Num b) => a -> b
fromIntegral (i -> DecimalRaw i) -> i -> DecimalRaw i
forall a b. (a -> b) -> a -> b
$ i -> i
forall a. Num a => a -> a
signum i
n
fromInteger :: Integer -> DecimalRaw i
fromInteger n :: Integer
n = Word8 -> i -> DecimalRaw i
forall i. Word8 -> i -> DecimalRaw i
Decimal 0 (i -> DecimalRaw i) -> i -> DecimalRaw i
forall a b. (a -> b) -> a -> b
$ Integer -> i
forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
n
instance (Integral i) => Real (DecimalRaw i) where
toRational :: DecimalRaw i -> Rational
toRational (Decimal e :: Word8
e n :: i
n) = i -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral i
n Integer -> Integer -> Rational
forall a. Integral a => a -> a -> Ratio a
% (10 Integer -> Word8 -> Integer
forall a b. (Num a, Integral b) => a -> b -> a
^ Word8
e)
instance (Integral i) => Fractional (DecimalRaw i) where
fromRational :: Rational -> DecimalRaw i
fromRational r :: Rational
r =
let
v :: Decimal
v :: Decimal
v = Decimal -> Decimal
forall i. Integral i => DecimalRaw i -> DecimalRaw i
normalizeDecimal (Decimal -> Decimal) -> Decimal -> Decimal
forall a b. (a -> b) -> a -> b
$ Word8 -> Rational -> Decimal
forall i r. (Integral i, RealFrac r) => Word8 -> r -> DecimalRaw i
realFracToDecimal Word8
forall a. Bounded a => a
maxBound Rational
r
in Decimal -> DecimalRaw i
forall a b.
(Integral a, Integral b) =>
DecimalRaw a -> DecimalRaw b
unsafeDecimalConvert Decimal
v
a :: DecimalRaw i
a / :: DecimalRaw i -> DecimalRaw i -> DecimalRaw i
/ b :: DecimalRaw i
b = Rational -> DecimalRaw i
forall a. Fractional a => Rational -> a
fromRational (Rational -> DecimalRaw i) -> Rational -> DecimalRaw i
forall a b. (a -> b) -> a -> b
$ DecimalRaw i -> Rational
forall a. Real a => a -> Rational
toRational DecimalRaw i
a Rational -> Rational -> Rational
forall a. Fractional a => a -> a -> a
/ DecimalRaw i -> Rational
forall a. Real a => a -> Rational
toRational DecimalRaw i
b
instance (Integral i) => RealFrac (DecimalRaw i) where
properFraction :: DecimalRaw i -> (b, DecimalRaw i)
properFraction a :: DecimalRaw i
a = (b
rnd, Rational -> DecimalRaw i
forall a. Fractional a => Rational -> a
fromRational Rational
rep)
where
(rnd :: b
rnd, rep :: Rational
rep) = Rational -> (b, Rational)
forall a b. (RealFrac a, Integral b) => a -> (b, a)
properFraction (Rational -> (b, Rational)) -> Rational -> (b, Rational)
forall a b. (a -> b) -> a -> b
$ DecimalRaw i -> Rational
forall a. Real a => a -> Rational
toRational DecimalRaw i
a
divide :: Decimal -> Int -> [(Int, Decimal)]
divide :: Decimal -> Int -> [(Int, Decimal)]
divide (Decimal e :: Word8
e n :: Integer
n) d :: Int
d
| Int
d Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> 0 =
case Integer
n Integer -> Integer -> (Integer, Integer)
forall a. Integral a => a -> a -> (a, a)
`divMod` Int -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
d of
(result :: Integer
result, 0) -> [(Int
d, Word8 -> Integer -> Decimal
forall i. Word8 -> i -> DecimalRaw i
Decimal Word8
e Integer
result)]
(result :: Integer
result, r :: Integer
r) -> [(Int
d Int -> Int -> Int
forall a. Num a => a -> a -> a
- Integer -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
r,
Word8 -> Integer -> Decimal
forall i. Word8 -> i -> DecimalRaw i
Decimal Word8
e Integer
result),
(Integer -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
r, Word8 -> Integer -> Decimal
forall i. Word8 -> i -> DecimalRaw i
Decimal Word8
e (Integer
resultInteger -> Integer -> Integer
forall a. Num a => a -> a -> a
+1))]
| Bool
otherwise = String -> [(Int, Decimal)]
forall a. HasCallStack => String -> a
error "Data.Decimal.divide: Divisor must be > 0."
allocate :: Decimal -> [Integer] -> [Decimal]
allocate :: Decimal -> [Integer] -> [Decimal]
allocate (Decimal e :: Word8
e n :: Integer
n) ps :: [Integer]
ps
| Integer
total Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
== 0 =
String -> [Decimal]
forall a. HasCallStack => String -> a
error "Data.Decimal.allocate: allocation list must not sum to zero."
| Bool
otherwise = (Integer -> Decimal) -> [Integer] -> [Decimal]
forall a b. (a -> b) -> [a] -> [b]
map (Word8 -> Integer -> Decimal
forall i. Word8 -> i -> DecimalRaw i
Decimal Word8
e) ([Integer] -> [Decimal]) -> [Integer] -> [Decimal]
forall a b. (a -> b) -> a -> b
$ (Integer -> Integer -> Integer)
-> [Integer] -> [Integer] -> [Integer]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith (-) [Integer]
ts ([Integer] -> [Integer]
forall a. [a] -> [a]
tail [Integer]
ts)
where
ts :: [Integer]
ts = ((Integer, Integer) -> Integer)
-> [(Integer, Integer)] -> [Integer]
forall a b. (a -> b) -> [a] -> [b]
map (Integer, Integer) -> Integer
forall a b. (a, b) -> a
fst ([(Integer, Integer)] -> [Integer])
-> [(Integer, Integer)] -> [Integer]
forall a b. (a -> b) -> a -> b
$ ((Integer, Integer) -> Integer -> (Integer, Integer))
-> (Integer, Integer) -> [Integer] -> [(Integer, Integer)]
forall b a. (b -> a -> b) -> b -> [a] -> [b]
scanl (Integer, Integer) -> Integer -> (Integer, Integer)
forall b. Integral b => (b, b) -> b -> (b, b)
nxt (Integer
n, Integer
total) [Integer]
ps
nxt :: (b, b) -> b -> (b, b)
nxt (n1 :: b
n1, t1 :: b
t1) p1 :: b
p1 = (b
n1 b -> b -> b
forall a. Num a => a -> a -> a
- (b
n1 b -> b -> b
forall a. Num a => a -> a -> a
* b
p1) b -> b -> b
forall a. Integral a => a -> a -> a
`zdiv` b
t1, b
t1 b -> b -> b
forall a. Num a => a -> a -> a
- b
p1)
zdiv :: p -> p -> p
zdiv 0 0 = 0
zdiv x :: p
x y :: p
y = p
x p -> p -> p
forall a. Integral a => a -> a -> a
`divRound` p
y
total :: Integer
total = [Integer] -> Integer
forall (t :: * -> *) a. (Foldable t, Num a) => t a -> a
sum [Integer]
ps
(*.) :: (Integral i, RealFrac r) => DecimalRaw i -> r -> DecimalRaw i
(Decimal e :: Word8
e m :: i
m) *. :: DecimalRaw i -> r -> DecimalRaw i
*. d :: r
d = Word8 -> i -> DecimalRaw i
forall i. Word8 -> i -> DecimalRaw i
Decimal Word8
e (i -> DecimalRaw i) -> i -> DecimalRaw i
forall a b. (a -> b) -> a -> b
$ r -> i
forall a b. (RealFrac a, Integral b) => a -> b
round (r -> i) -> r -> i
forall a b. (a -> b) -> a -> b
$ i -> r
forall a b. (Integral a, Num b) => a -> b
fromIntegral i
m r -> r -> r
forall a. Num a => a -> a -> a
* r
d
factorN :: (Integral a)
=> a
-> a
-> (a, a)
factorN :: a -> a -> (a, a)
factorN d :: a
d val :: a
val = a -> a -> (a, a)
forall t. Num t => a -> t -> (t, a)
factorN' a
val 0
where
factorN' :: a -> t -> (t, a)
factorN' 1 acc :: t
acc = (t
acc, 1)
factorN' v :: a
v acc :: t
acc = if a
md a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== 0
then a -> t -> (t, a)
factorN' a
vd (t
acc t -> t -> t
forall a. Num a => a -> a -> a
+ 1)
else (t
acc, a
v)
where
(vd :: a
vd, md :: a
md) = a
v a -> a -> (a, a)
forall a. Integral a => a -> a -> (a, a)
`divMod` a
d
eitherFromRational :: (Integral i) => Rational -> Either String (DecimalRaw i)
eitherFromRational :: Rational -> Either String (DecimalRaw i)
eitherFromRational r :: Rational
r = if Integer
done Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
== 1
then do
Word8
wres <- Either String Word8
we
DecimalRaw i -> Either String (DecimalRaw i)
forall (m :: * -> *) a. Monad m => a -> m a
return (DecimalRaw i -> Either String (DecimalRaw i))
-> DecimalRaw i -> Either String (DecimalRaw i)
forall a b. (a -> b) -> a -> b
$ Word8 -> i -> DecimalRaw i
forall i. Word8 -> i -> DecimalRaw i
Decimal Word8
wres (Integer -> i
forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
m)
else String -> Either String (DecimalRaw i)
forall a b. a -> Either a b
Left (String -> Either String (DecimalRaw i))
-> String -> Either String (DecimalRaw i)
forall a b. (a -> b) -> a -> b
$ Rational -> String
forall a. Show a => a -> String
show Rational
r String -> ShowS
forall a. [a] -> [a] -> [a]
++ " has no decimal denominator"
where
den :: Integer
den = Rational -> Integer
forall a. Ratio a -> a
denominator Rational
r
num :: Integer
num = Rational -> Integer
forall a. Ratio a -> a
numerator Rational
r
(f2 :: Integer
f2, rest :: Integer
rest) = Integer -> Integer -> (Integer, Integer)
forall a. Integral a => a -> a -> (a, a)
factorN 2 Integer
den
(f5 :: Integer
f5, done :: Integer
done) = Integer -> Integer -> (Integer, Integer)
forall a. Integral a => a -> a -> (a, a)
factorN 5 Integer
rest
e :: Integer
e = Integer -> Integer -> Integer
forall a. Ord a => a -> a -> a
max Integer
f2 Integer
f5
m :: Integer
m = Integer
num Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* ((10Integer -> Integer -> Integer
forall a b. (Num a, Integral b) => a -> b -> a
^Integer
e) Integer -> Integer -> Integer
forall a. Integral a => a -> a -> a
`div` Integer
den)
we :: Either String Word8
we = if Integer
e Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
> Word8 -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word8
forall a. Bounded a => a
maxBound :: Word8)
then String -> Either String Word8
forall a b. a -> Either a b
Left (String -> Either String Word8) -> String -> Either String Word8
forall a b. (a -> b) -> a -> b
$ Integer -> String
forall a. Show a => a -> String
show Integer
e String -> ShowS
forall a. [a] -> [a] -> [a]
++ " is too big ten power to represent as Decimal"
else Word8 -> Either String Word8
forall a b. b -> Either a b
Right (Word8 -> Either String Word8) -> Word8 -> Either String Word8
forall a b. (a -> b) -> a -> b
$ Integer -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral Integer
e
normalizeDecimal :: (Integral i) => DecimalRaw i -> DecimalRaw i
normalizeDecimal :: DecimalRaw i -> DecimalRaw i
normalizeDecimal r :: DecimalRaw i
r = case Rational -> Either String (DecimalRaw i)
forall i. Integral i => Rational -> Either String (DecimalRaw i)
eitherFromRational (Rational -> Either String (DecimalRaw i))
-> Rational -> Either String (DecimalRaw i)
forall a b. (a -> b) -> a -> b
$ DecimalRaw i -> Rational
forall a. Real a => a -> Rational
toRational DecimalRaw i
r of
Right x :: DecimalRaw i
x -> DecimalRaw i
x
Left e :: String
e -> String -> DecimalRaw i
forall a. HasCallStack => String -> a
error (String -> DecimalRaw i) -> String -> DecimalRaw i
forall a b. (a -> b) -> a -> b
$ "Impossible happened: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
e