--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/Pure/General/rat.ML Fri Oct 14 14:36:39 2005 +0200
@@ -0,0 +1,105 @@
+(* Title: Pure/General/rat.ML
+ ID: $Id$
+ Author: Tobias Nipkow, TU Muenchen
+
+Canonical implementation of exact rational numbers
+*)
+
+signature RAT =
+sig
+ type rat
+ exception DIVZERO
+ val zero: rat
+ val rat_of_int: int -> rat
+ val rat_of_intinf: IntInf.int -> rat
+ val rat_of_quotient: IntInf.int * IntInf.int -> rat
+ val quotient_of_rat: rat -> IntInf.int * IntInf.int
+ val string_of_rat: rat -> string
+ val eq: rat * rat -> bool
+ val le: rat * rat -> bool
+ val lt: rat * rat -> bool
+ val ord: rat * rat -> order
+ val add: rat * rat -> rat
+ val mult: rat * rat -> rat
+ val neg: rat -> rat
+ val inv: rat -> rat
+ val ge0: rat -> bool
+ val gt0: rat -> bool
+end;
+
+structure Rat: RAT =
+struct
+
+(*keep them normalized!*)
+
+datatype rat = Rat of bool * IntInf.int * IntInf.int;
+
+exception DIVZERO;
+
+val zero = Rat (true, 0, 1);
+
+fun rat_of_intinf i =
+ if i < 0
+ then Rat (false, ~i, 1)
+ else Rat (true, i, 1);
+
+fun rat_of_int i = rat_of_intinf (IntInf.fromInt i);
+
+fun norm (a, 0, q) =
+ Rat (true, 0, 1) (* is that intentional? *)
+ | norm (a, p, q) =
+ let
+ val absp = abs p
+ val m = gcd (absp, q)
+ in Rat(a = (0 <= p), absp div m, q div m) end;
+
+fun common (p1, q1, p2, q2) =
+ let val q' = lcm (q1, q2)
+ in (p1 * (q' div q1), p2 * (q' div q2), q') end
+
+fun rat_of_quotient (p, 0) =
+ raise DIVZERO
+ | rat_of_quotient (p, q) =
+ norm (0 <= q, p, abs q);
+
+fun quotient_of_rat (Rat (a, p, q)) = (if a then p else ~p, q);
+
+fun string_of_rat r =
+ let val (p, q) = quotient_of_rat r
+ in IntInf.toString p ^ "/" ^ IntInf.toString q end;
+
+fun ord (Rat (false, _, _), Rat (true, _, _)) = LESS
+ | ord (Rat (true, _, _), Rat (false, _, _)) = GREATER
+ | ord (Rat (a, p1, q1), Rat (_, p2, q2)) =
+ if p1 = p2 andalso q1 = q2 then EQUAL
+ else let val (r1, r2, _) = common (p1, q1, p2, q2)
+ in if a then IntInf.compare (r1, r2) else IntInf.compare (r2, r1) end;
+
+fun eq r = (ord r = EQUAL);
+
+fun le r = not (ord r = GREATER);
+
+fun lt r = (ord r = LESS);
+
+fun add (Rat (a1, p1, q1), Rat(a2, p2, q2)) =
+ let
+ val (r1, r2, den) = common (p1, q1, p2, q2)
+ val num = (if a1 then r1 else ~r1) + (if a2 then r2 else ~r2)
+ in norm (true, num, den) end;
+
+fun mult (Rat (a1, p1, q1), Rat (a2, p2, q2)) =
+ norm (a1=a2, p1*p2, q1*q2);
+
+fun neg (r as Rat (_, 0, _)) = r
+ | neg (Rat (b, p, q)) =
+ Rat (not b, p, q);
+
+fun inv (Rat (a, 0, q)) =
+ raise DIVZERO
+ | inv (Rat (a, p, q)) =
+ Rat (a, q, p)
+
+fun ge0 (Rat (a, _, _)) = a;
+fun gt0 (Rat (a, p, _)) = a andalso p > 0;
+
+end;