diff -r 5d5cada76409 -r de5d9d5e99f5 src/Pure/General/rat.ML --- /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;