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