module Data.DFrac (DFrac(..), setPrec) where import GHC.Read import Data.Ratio import Data.Scientific data DFrac = DFrac { places :: Int, number :: Rational } instance Eq DFrac where x == y = number x == number y && places x == places y instance Ord DFrac where compare x y = case compare (number x) (number y) of EQ -> compare (places x) (places y) c -> c instance Num DFrac where x + y = dfrac min x y $ number x + number y x - y = dfrac min x y $ number x - number y x * y = dfrac min x y $ number x * number y abs x = DFrac (places x) $ abs $ number x signum x = DFrac (places x) $ signum $ number x fromInteger = DFrac 16 . fromInteger instance Fractional DFrac where x / y = dfrac min x y $ number x / number y fromRational = DFrac 16 . fromRational instance Real DFrac where toRational = number instance RealFrac DFrac where properFraction x = (a, DFrac (places x) b) where (a, b) = properFraction $ number x instance Read DFrac where readsPrec p z = map (\(d, s) -> (DFrac 16 $ toRational d, s)) r where r :: [(Scientific, String)] r = readsPrec p z readListPrec = readListPrecDefault readList = readListDefault instance Show DFrac where show (DFrac p r) = show i ++ "." ++ (tail $ show f) where n = numerator r d = denominator r i = n `div` d f :: Integer f = (10^p) + (truncate $ (10^p) * (snd $ properFraction r)) setPrec :: Int -> DFrac -> DFrac setPrec p r = r { places = p } dfrac :: (Int -> Int -> Int) -> DFrac -> DFrac -> Rational -> DFrac dfrac f x y z = DFrac (prec f x y) z prec :: (Int -> Int -> Int) -> DFrac -> DFrac -> Int prec f x y = f (places x) (places y)