{-# LANGUAGE BangPatterns #-} {-| Module : Math.ExpPairs.RatioInf Description : Rational numbers with infinities Copyright : (c) Andrew Lelechenko, 2014-2015 License : GPL-3 Maintainer : andrew.lelechenko@gmail.com Stability : experimental Portability : POSIX Provides types and necessary instances for rational numbers, extended with infinite values. Just use 'RationalInf' instead of 'Rational' from "Data.Ratio". -} module Math.ExpPairs.RatioInf ( RatioInf (..) , RationalInf ) where import Data.Ratio (Ratio) -- |Extends a rational type with positive and negative -- infinities. data RatioInf t -- |Negative infinity = InfMinus -- |Finite value | Finite !(Ratio t) -- |Positive infinity | InfPlus deriving (Ord, Eq) -- |Arbitrary-precision rational numbers with positive and negative -- infinities. type RationalInf = RatioInf Integer instance (Integral t, Show t) => Show (RatioInf t) where show InfMinus = "-Inf" show (Finite x) = show x show InfPlus = "+Inf" instance Integral t => Num (RatioInf t) where InfMinus + InfPlus = error "Cannot add up negative and positive infinities" InfPlus + InfMinus = error "Cannot add up negative and positive infinities" InfMinus + _ = InfMinus InfPlus + _ = InfPlus _ + InfMinus = InfMinus _ + InfPlus = InfPlus (Finite a) + (Finite b) = Finite (a+b) fromInteger = Finite . fromInteger signum InfMinus = Finite (-1) signum InfPlus = Finite 1 signum (Finite r) = Finite (signum r) abs InfMinus = InfPlus abs InfPlus = InfPlus abs (Finite r) = Finite (abs r) negate InfMinus = InfPlus negate InfPlus = InfMinus negate (Finite r) = Finite (negate r) InfMinus * InfMinus = InfMinus InfMinus * InfPlus = InfMinus InfMinus * Finite a = case signum a of 1 -> InfMinus -1 -> InfPlus _ -> error "Cannot multiply infinity by zero" InfPlus * InfMinus = InfMinus InfPlus * InfPlus = InfPlus InfPlus * Finite a = case signum a of 1 -> InfPlus -1 -> InfMinus _ -> error "Cannot multiply infinity by zero" Finite a * InfMinus = case signum a of 1 -> InfMinus -1 -> InfPlus _ -> error "Cannot multiply infinity by zero" Finite a * InfPlus = case signum a of 1 -> InfPlus -1 -> InfMinus _ -> error "Cannot multiply infinity by zero" Finite a * Finite b = Finite (a * b) instance Integral t => Fractional (RatioInf t) where fromRational = Finite . fromRational InfMinus / InfMinus = error "Cannot divide infinity by infinity" InfMinus / InfPlus = error "Cannot divide infinity by infinity" InfMinus / Finite a = case signum a of 1 -> InfMinus -1 -> InfPlus _ -> error "Cannot divide infinity by zero" InfPlus / InfMinus = error "Cannot divide infinity by infinity" InfPlus / InfPlus = error "Cannot divide infinity by infinity" InfPlus / Finite a = case signum a of 1 -> InfPlus -1 -> InfMinus _ -> error "Cannot divide infinity by zero" Finite _ / InfPlus = Finite 0 Finite _ / InfMinus = Finite 0 Finite _ / Finite 0 = error "Cannot divide finite value by zero" Finite a / Finite b = Finite (a/b) instance Integral t => Real (RatioInf t) where toRational (Finite r) = toRational r toRational InfPlus = error "Cannot map infinity into Rational" toRational InfMinus = error "Cannot map infinity into Rational"