> module Rationals
> (Rationals(..),rndNR)
> where
> import Ratio--1.3
> infix 7 :%%
Data declaration for Rationals.
Rationals are defined in terms of Ints.
> data Rationals = Int :%% Int deriving (Show{-was:Text-},Eq)
LazyRationals instance of Ord declared with
simple degeneration to lazyInteger where
numerators are multiplied by opposite denumerators.
> instance Ord Rationals where
> (p :%% q) <= (r :%% s) = p*s <= q*r
> instance Num Rationals where
(+): rational addition is performed by converting
the arguments to a form where they share a common
denominator.
The function simplify ensures that the answer
is in normal form.
Unit denominators are treated as special cases.
> (+) (p :%% 1) (r :%% 1) = (p+r) :%% 1
> (+) (p :%% 1) (r :%% s) = simplify (p*s +r) s
> (+) (p :%% q) (r :%% 1) = simplify (p+ q*r) q
> (+) (p :%% q) (r :%% s) = simplify (p*s+q*r) (q*s)
Multiplication of rationals provided by degeneration
to Ints. Unit denominators are treated as special
cases.
> (*) (p :%% 1) (r :%% 1) = (p*r) :%% 1
> (*) (p :%% 1) (r :%% s) = simplify (p*r) s
> (*) (p :%% q) (r :%% 1) = simplify (p*r) q
> (*) (p :%% q) (r :%% s) = simplify (p*r) (q*s)
negate: Simply change the sign of the numerator to negate
> negate (x :%% y) = (negate x :%% y)
abs: Take the abs value of the numerator and place over the
denominator
> abs (x :%% y) = (abs x :%% y)
signum: sign simply determined by sign of numerator
> signum (x :%% _) = (signum x:%%1)
fromInteger: Change to an Integer and stick it over one.
> fromInteger x = (fromInteger x) :%% 1
defines LazyRational as a instance of the class Fractional
> instance Fractional Rationals where
divideLazyNum: performed by turning over second Rational
and multiplying.
Zero cases handled appropriately.
> (/) x y@(r :%% s) | r==0 = error "Attempt to divide by Zero"
> | otherwise = x * (s :%% r)
fromRational : defines conversion of a Rational
(Ratio Integer) to Rationals. NB Rational
is supposedly in normal form.
> fromRational r = (fromInteger (numerator r)) :%% (fromInteger (denominator r))
simplify: produces a Rational in normal
form from the Ints given. Note normal
form means a positive denominator. Sign
of numerator therefore determines sign of number.
> simplify :: Int -> Int -> Rationals
> simplify x y = (signum bottom*top) :%% abs bottom
> where
> top = x `div` d
> bottom = y `div` d
> d = gcd x y
Defines Rationals as a member of the class Real.
> instance Real Rationals where
> toRational (x:%%y) = toInteger x % toInteger y
> instance Enum Rationals where -- partain
> enumFrom = error "Enum.Rationals.enumFrom"
> enumFromThen = error "Enum.Rationals.enumFromThen"
> enumFromTo = error "Enum.Rationals.enumFromTo"
> enumFromThenTo = error "Enum.Rationals.enumFromThenTo"
top : extracts the numerator part of a rational
> top :: Rationals -> Int
> top (a :%% b) = a
bottom : extract the denominator part of a rational
> bottom :: Rationals -> Int
> bottom (a :%% b) = b
rndNR : Converts a Rational to an Int. Rounding to the
nearest. NB: Safe to use Int. Only results
that lie on screen are arguments to rndNR.
NB: Also no need to worry about rounding
negative strategy for same reason.
> rndNR :: Rationals -> Int
> rndNR (a :%% 1) = fromInteger (toInteger a)
> rndNR a = fromInteger (toInteger (div n d))
> where r = (1/2) + a
> n = top r
> d = bottom r
|