{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveLift #-}
module Argo.Type.Decimal where
import Data.Ratio ((%))
import qualified Argo.Vendor.DeepSeq as DeepSeq
import qualified Argo.Vendor.TemplateHaskell as TH
import qualified Data.Ratio as Ratio
import qualified GHC.Generics as Generics
data Decimal = Decimal Integer Integer
deriving (Decimal -> Decimal -> Bool
(Decimal -> Decimal -> Bool)
-> (Decimal -> Decimal -> Bool) -> Eq Decimal
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Decimal -> Decimal -> Bool
$c/= :: Decimal -> Decimal -> Bool
== :: Decimal -> Decimal -> Bool
$c== :: Decimal -> Decimal -> Bool
Eq, (forall x. Decimal -> Rep Decimal x)
-> (forall x. Rep Decimal x -> Decimal) -> Generic Decimal
forall x. Rep Decimal x -> Decimal
forall x. Decimal -> Rep Decimal x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep Decimal x -> Decimal
$cfrom :: forall x. Decimal -> Rep Decimal x
Generics.Generic, Decimal -> Q Exp
Decimal -> Q (TExp Decimal)
(Decimal -> Q Exp) -> (Decimal -> Q (TExp Decimal)) -> Lift Decimal
forall t. (t -> Q Exp) -> (t -> Q (TExp t)) -> Lift t
liftTyped :: Decimal -> Q (TExp Decimal)
$cliftTyped :: Decimal -> Q (TExp Decimal)
lift :: Decimal -> Q Exp
$clift :: Decimal -> Q Exp
TH.Lift, Decimal -> ()
(Decimal -> ()) -> NFData Decimal
forall a. (a -> ()) -> NFData a
rnf :: Decimal -> ()
$crnf :: Decimal -> ()
DeepSeq.NFData, Int -> Decimal -> ShowS
[Decimal] -> ShowS
Decimal -> String
(Int -> Decimal -> ShowS)
-> (Decimal -> String) -> ([Decimal] -> ShowS) -> Show Decimal
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Decimal] -> ShowS
$cshowList :: [Decimal] -> ShowS
show :: Decimal -> String
$cshow :: Decimal -> String
showsPrec :: Int -> Decimal -> ShowS
$cshowsPrec :: Int -> Decimal -> ShowS
Show)
negate :: Decimal -> Decimal
negate :: Decimal -> Decimal
negate (Decimal Integer
s Integer
e) = Integer -> Integer -> Decimal
Decimal (-Integer
s) Integer
e
decimal :: Integer -> Integer -> Decimal
decimal :: Integer -> Integer -> Decimal
decimal Integer
s = Decimal -> Decimal
normalize (Decimal -> Decimal) -> (Integer -> Decimal) -> Integer -> Decimal
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Integer -> Integer -> Decimal
Decimal Integer
s
normalize :: Decimal -> Decimal
normalize :: Decimal -> Decimal
normalize (Decimal Integer
s Integer
e) = if Integer
s Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
== Integer
0
then Integer -> Integer -> Decimal
Decimal Integer
0 Integer
0
else
let (Integer
q, Integer
r) = Integer -> Integer -> (Integer, Integer)
forall a. Integral a => a -> a -> (a, a)
quotRem Integer
s Integer
10
in if Integer
r Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
== Integer
0 then Decimal -> Decimal
normalize (Decimal -> Decimal) -> Decimal -> Decimal
forall a b. (a -> b) -> a -> b
$ Integer -> Integer -> Decimal
Decimal Integer
q (Integer
e Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
+ Integer
1) else Integer -> Integer -> Decimal
Decimal Integer
s Integer
e
toRational :: Decimal -> Rational
toRational :: Decimal -> Rational
toRational (Decimal Integer
s Integer
e) =
if Integer
e Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
< Integer
0 then Integer
s Integer -> Integer -> Rational
forall a. Integral a => a -> a -> Ratio a
% (Integer
10 Integer -> Integer -> Integer
forall a b. (Num a, Integral b) => a -> b -> a
^ (-Integer
e)) else Integer -> Rational
forall a. Num a => Integer -> a
fromInteger (Integer -> Rational) -> Integer -> Rational
forall a b. (a -> b) -> a -> b
$ Integer
s 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
e
fromRational :: Rational -> Maybe Decimal
fromRational :: Rational -> Maybe Decimal
fromRational Rational
r =
let
n :: Integer
n = Rational -> Integer
forall a. Ratio a -> a
Ratio.numerator Rational
r
d1 :: Integer
d1 = Rational -> Integer
forall a. Ratio a -> a
Ratio.denominator Rational
r
(Integer
t, Integer
d2) = Integer -> Integer -> Integer -> (Integer, Integer)
forall a b. (Num a, Integral b) => b -> a -> b -> (a, b)
factor Integer
2 (Integer
0 :: Integer) Integer
d1
(Integer
f, Integer
d3) = Integer -> Integer -> Integer -> (Integer, Integer)
forall a b. (Num a, Integral b) => b -> a -> b -> (a, b)
factor Integer
5 (Integer
0 :: Integer) Integer
d2
p :: Integer
p = Integer -> Integer -> Integer
forall a. Ord a => a -> a -> a
max Integer
t Integer
f
in if Integer
d3 Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
== Integer
1
then Decimal -> Maybe Decimal
forall a. a -> Maybe a
Just (Decimal -> Maybe Decimal) -> Decimal -> Maybe Decimal
forall a b. (a -> b) -> a -> b
$ Integer -> Integer -> Decimal
decimal (Integer
n Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
2 Integer -> Integer -> Integer
forall a b. (Num a, Integral b) => a -> b -> a
^ (Integer
p Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
- Integer
t) Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
* Integer
5 Integer -> Integer -> Integer
forall a b. (Num a, Integral b) => a -> b -> a
^ (Integer
p Integer -> Integer -> Integer
forall a. Num a => a -> a -> a
- Integer
f)) (-Integer
p)
else Maybe Decimal
forall a. Maybe a
Nothing
factor :: (Num a, Integral b) => b -> a -> b -> (a, b)
factor :: b -> a -> b -> (a, b)
factor b
d a
n b
x =
let (b
q, b
r) = b -> b -> (b, b)
forall a. Integral a => a -> a -> (a, a)
quotRem b
x b
d
in if b
x b -> b -> Bool
forall a. Eq a => a -> a -> Bool
/= b
0 Bool -> Bool -> Bool
&& b
r b -> b -> Bool
forall a. Eq a => a -> a -> Bool
== b
0 then b -> a -> b -> (a, b)
forall a b. (Num a, Integral b) => b -> a -> b -> (a, b)
factor b
d (a
n a -> a -> a
forall a. Num a => a -> a -> a
+ a
1) b
q else (a
n, b
x)