| 17848 |      1 | (*  Title:      Pure/General/rat.ML
 | 
|  |      2 |     ID:         $Id$
 | 
|  |      3 |     Author:     Tobias Nipkow, TU Muenchen
 | 
|  |      4 | 
 | 
| 17940 |      5 | Canonical implementation of exact rational numbers.
 | 
| 17848 |      6 | *)
 | 
|  |      7 | 
 | 
|  |      8 | signature RAT =
 | 
|  |      9 | sig
 | 
|  |     10 |   type rat
 | 
|  |     11 |   exception DIVZERO
 | 
|  |     12 |   val zero: rat
 | 
|  |     13 |   val rat_of_int: int -> rat
 | 
|  |     14 |   val rat_of_intinf: IntInf.int -> rat
 | 
|  |     15 |   val rat_of_quotient: IntInf.int * IntInf.int -> rat
 | 
|  |     16 |   val quotient_of_rat: rat -> IntInf.int * IntInf.int
 | 
|  |     17 |   val string_of_rat: rat -> string
 | 
|  |     18 |   val eq: rat * rat -> bool
 | 
|  |     19 |   val le: rat * rat -> bool
 | 
|  |     20 |   val lt: rat * rat -> bool
 | 
|  |     21 |   val ord: rat * rat -> order
 | 
|  |     22 |   val add: rat * rat -> rat
 | 
|  |     23 |   val mult: rat * rat -> rat
 | 
|  |     24 |   val neg: rat -> rat
 | 
|  |     25 |   val inv: rat -> rat
 | 
|  |     26 |   val ge0: rat -> bool
 | 
|  |     27 |   val gt0: rat -> bool
 | 
| 17940 |     28 |   val roundup: rat -> rat
 | 
|  |     29 |   val rounddown: rat -> rat
 | 
| 17848 |     30 | end;
 | 
|  |     31 | 
 | 
|  |     32 | structure Rat: RAT =
 | 
|  |     33 | struct
 | 
|  |     34 | 
 | 
|  |     35 | (*keep them normalized!*)
 | 
|  |     36 | 
 | 
|  |     37 | datatype rat = Rat of bool * IntInf.int * IntInf.int;
 | 
|  |     38 | 
 | 
|  |     39 | exception DIVZERO;
 | 
|  |     40 | 
 | 
|  |     41 | val zero = Rat (true, 0, 1);
 | 
|  |     42 | 
 | 
|  |     43 | fun rat_of_intinf i =
 | 
|  |     44 |   if i < 0
 | 
|  |     45 |   then Rat (false, ~i, 1)
 | 
|  |     46 |   else Rat (true, i, 1);
 | 
|  |     47 | 
 | 
|  |     48 | fun rat_of_int i = rat_of_intinf (IntInf.fromInt i);
 | 
|  |     49 | 
 | 
|  |     50 | fun norm (a, 0, q) =
 | 
| 17950 |     51 |       Rat (true, 0, 1)
 | 
| 17848 |     52 |   | norm (a, p, q) =
 | 
|  |     53 |       let
 | 
|  |     54 |         val absp = abs p
 | 
|  |     55 |         val m = gcd (absp, q)
 | 
|  |     56 |       in Rat(a = (0 <= p), absp div m, q div m) end;
 | 
|  |     57 | 
 | 
|  |     58 | fun common (p1, q1, p2, q2) =
 | 
|  |     59 |   let val q' = lcm (q1, q2)
 | 
|  |     60 |   in (p1 * (q' div q1), p2 * (q' div q2), q') end
 | 
|  |     61 | 
 | 
|  |     62 | fun rat_of_quotient (p, 0) =
 | 
|  |     63 |       raise DIVZERO
 | 
|  |     64 |   | rat_of_quotient (p, q) =
 | 
|  |     65 |       norm (0 <= q, p, abs q);
 | 
|  |     66 | 
 | 
|  |     67 | fun quotient_of_rat (Rat (a, p, q)) = (if a then p else ~p, q);
 | 
|  |     68 | 
 | 
|  |     69 | fun string_of_rat r =
 | 
|  |     70 |   let val (p, q) = quotient_of_rat r
 | 
|  |     71 |   in IntInf.toString p ^ "/" ^ IntInf.toString q end;
 | 
|  |     72 | 
 | 
| 17940 |     73 | fun eq (Rat (false, _, _), Rat (true, _, _)) = false
 | 
|  |     74 |   | eq (Rat (true, _, _), Rat (false, _, _)) = false
 | 
|  |     75 |   | eq (Rat (_, p1, q1), Rat (_, p2, q2)) = p1 = p2 andalso q1 = q2
 | 
|  |     76 | 
 | 
|  |     77 | fun le (Rat (false, _, _), Rat (true, _, _)) = true
 | 
|  |     78 |   | le (Rat (true, _, _), Rat (false, _, _)) = false
 | 
|  |     79 |   | le (Rat (a, p1, q1), Rat (_, p2, q2)) =
 | 
|  |     80 |       let val (r1, r2, _) = common (p1, q1, p2, q2)
 | 
|  |     81 |       in if a then r1 <= r2 else r2 <= r1 end;
 | 
|  |     82 | 
 | 
|  |     83 | fun lt (Rat (false, _, _), Rat (true, _, _)) = true
 | 
|  |     84 |   | lt (Rat (true, _, _), Rat (false, _, _)) = false
 | 
|  |     85 |   | lt (Rat (a, p1, q1), Rat (_, p2, q2)) =
 | 
|  |     86 |       let val (r1, r2, _) = common (p1, q1, p2, q2)
 | 
|  |     87 |       in if a then r1 <= r2 else r2 <= r1 end;
 | 
|  |     88 | 
 | 
| 17848 |     89 | fun ord (Rat (false, _, _), Rat (true, _, _)) = LESS
 | 
|  |     90 |   | ord (Rat (true, _, _), Rat (false, _, _)) = GREATER
 | 
|  |     91 |   | ord (Rat (a, p1, q1), Rat (_, p2, q2)) =
 | 
| 17940 |     92 |       let val (r1, r2, _) = common (p1, q1, p2, q2)
 | 
| 17848 |     93 |       in if a then IntInf.compare (r1, r2) else IntInf.compare (r2, r1) end;
 | 
|  |     94 | 
 | 
|  |     95 | fun add (Rat (a1, p1, q1), Rat(a2, p2, q2)) =
 | 
|  |     96 |   let
 | 
|  |     97 |     val (r1, r2, den) = common (p1, q1, p2, q2)
 | 
|  |     98 |     val num = (if a1 then r1 else ~r1) + (if a2 then r2 else ~r2)
 | 
|  |     99 |   in norm (true, num, den) end;
 | 
|  |    100 | 
 | 
|  |    101 | fun mult (Rat (a1, p1, q1), Rat (a2, p2, q2)) =
 | 
|  |    102 |   norm (a1=a2, p1*p2, q1*q2);
 | 
|  |    103 | 
 | 
|  |    104 | fun neg (r as Rat (_, 0, _)) = r
 | 
|  |    105 |   | neg (Rat (b, p, q)) =
 | 
|  |    106 |       Rat (not b, p, q);
 | 
|  |    107 | 
 | 
|  |    108 | fun inv (Rat (a, 0, q)) =
 | 
|  |    109 |       raise DIVZERO
 | 
|  |    110 |   | inv (Rat (a, p, q)) =
 | 
|  |    111 |       Rat (a, q, p)
 | 
|  |    112 | 
 | 
|  |    113 | fun ge0 (Rat (a, _, _)) = a;
 | 
|  |    114 | fun gt0 (Rat (a, p, _)) = a andalso p > 0;
 | 
|  |    115 | 
 | 
| 17940 |    116 | fun roundup (r as Rat (_, _, 1)) = r
 | 
|  |    117 |   | roundup (Rat (a, p, q)) =
 | 
|  |    118 |       let
 | 
|  |    119 |         fun round true q = Rat (true, q+1, 1)
 | 
|  |    120 |           | round false 0 = Rat (true, 0 ,1)
 | 
|  |    121 |           | round false q = Rat (false, q, 1)
 | 
|  |    122 |       in round a (p div q) end;
 | 
|  |    123 | 
 | 
|  |    124 | fun rounddown (r as Rat (_, _, 1)) = r
 | 
|  |    125 |   | rounddown (Rat (a, p, q)) =
 | 
|  |    126 |       let
 | 
|  |    127 |         fun round true q = Rat (true, q, 1)
 | 
|  |    128 |           | round false q = Rat (false, q+1, 1)
 | 
|  |    129 |       in round a (p div q) end;
 | 
|  |    130 | 
 | 
| 17848 |    131 | end;
 |