From a619e63030316f5b16a799e1b9d43be66b77a322 Mon Sep 17 00:00:00 2001 From: Raymond Hogenson Date: Sun, 18 Nov 2018 00:33:43 -0500 Subject: Add rational numbers Now calculations are done to arbitrary precision if possible. --- RealCalc.hs | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) (limited to 'RealCalc.hs') diff --git a/RealCalc.hs b/RealCalc.hs index ac8ecb5..d54cf84 100644 --- a/RealCalc.hs +++ b/RealCalc.hs @@ -22,27 +22,42 @@ module RealCalc (calculate) where import qualified Expr +import qualified Data.Ratio -data Result = RInt Integer | RFloat Double +data Result = RInt Integer | RFloat Double | RRatio Rational + +data ResultPair = RInts Integer Integer | RFloats Double Double | RRatios Rational Rational instance Show Result where show (RInt i) = show i show (RFloat d) = show d + show (RRatio r) = show (Data.Ratio.numerator r) ++ "/" ++ show (Data.Ratio.denominator r) rToDouble :: Result -> Double rToDouble (RInt i) = fromIntegral i rToDouble (RFloat d) = d +rToDouble (RRatio r) = fromIntegral (Data.Ratio.numerator r) / fromIntegral (Data.Ratio.denominator r) + +castSame :: Result -> Result -> ResultPair +castSame a (RFloat b) = RFloats (rToDouble a) b +castSame (RFloat a) b = RFloats a (rToDouble b) +castSame (RRatio a) (RRatio b) = RRatios a b +castSame (RInt a) (RRatio b) = RRatios (fromIntegral a) b +castSame (RInt a) (RInt b) = RInts a b +castSame (RRatio a) (RInt b) = RRatios a (fromIntegral b) genericCombine :: (forall a. Num a => a -> a -> a) -> Result -> Result -> Result genericCombine f i j = - case (i, j) of - (RInt a, RInt b) -> RInt (f a b) - _ -> RFloat (f (rToDouble i) (rToDouble j)) + case castSame i j of + RInts a b -> RInt (f a b) + RFloats a b -> RFloat (f a b) + RRatios a b -> RRatio (f a b) genericInner :: (forall a. Num a => a -> a) -> Result -> Result genericInner f (RInt i) = RInt (f i) genericInner f (RFloat d) = RFloat (f d) +genericInner f (RRatio r) = RRatio (f r) simplify :: Expr.Expr -> Result simplify (Expr.Plus e1 e2) = @@ -53,13 +68,17 @@ simplify (Expr.Minus e1 e2) = simplify (Expr.Times e1 e2) = genericCombine (*) (simplify e1) (simplify e2) simplify (Expr.Div e1 e2) = - RFloat (rToDouble (simplify e1) / rToDouble (simplify e2)) + case castSame (simplify e1) (simplify e2) of + RInts a b -> RRatio (a Data.Ratio.% b) + RRatios a b -> RRatio (a / b) + RFloats a b -> RFloat (a / b) simplify (Expr.Pow e1 e2) = case (simplify e1, simplify e2) of (RInt a, RInt b) | b >= 0 -> RInt (a ^ b) - (a, RInt b) -> RFloat (rToDouble a ^^ b) - (a, RFloat b) -> RFloat (rToDouble a ** b) + (RRatio a, RInt b) -> RRatio (a ^^ b) + (RFloat a, RInt b) -> RFloat (a ^^ b) + (a, b) -> RFloat (rToDouble a ** rToDouble b) simplify (Expr.EInt i) = RInt i simplify (Expr.EFloat d) = RFloat d simplify Expr.E = RFloat (exp 1) -- cgit v1.3.1