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