src/Pure/General/rat.ML
changeset 22574 e6c25fd3de2a
parent 22189 10278e568741
child 22950 8b6d28fc6532
equal deleted inserted replaced
22573:2ac646ab2f6c 22574:e6c25fd3de2a
    37 
    37 
    38 datatype rat = Rat of bool * IntInf.int * IntInf.int;
    38 datatype rat = Rat of bool * IntInf.int * IntInf.int;
    39 
    39 
    40 exception DIVZERO;
    40 exception DIVZERO;
    41 
    41 
    42 val zero = Rat (true, 0, 1);
    42 val zero = Rat (true, IntInf.fromInt 0, IntInf.fromInt 1);
    43 
    43 
    44 val one = Rat (true, 1, 1);
    44 val one = Rat (true, IntInf.fromInt 1, IntInf.fromInt 1);
    45 
    45 
    46 fun rat_of_intinf i =
    46 fun rat_of_intinf i =
    47   if i < 0
    47   if i < IntInf.fromInt 0
    48   then Rat (false, ~i, 1)
    48   then Rat (false, ~i, IntInf.fromInt 1)
    49   else Rat (true, i, 1);
    49   else Rat (true, i, IntInf.fromInt 1);
    50 
    50 
    51 fun rat_of_int i = rat_of_intinf (IntInf.fromInt i);
    51 fun rat_of_int i = rat_of_intinf (IntInf.fromInt i);
    52 
    52 
    53 fun norm (a, 0, q) =
    53 fun norm (a, p, q) =
    54       Rat (true, 0, 1)
    54   if p = IntInf.fromInt 0 then Rat (true, IntInf.fromInt 0, IntInf.fromInt 1)
    55   | norm (a, p, q) =
    55   else
    56       let
    56     let
    57         val absp = abs p
    57       val absp = abs p
    58         val m = gcd (absp, q)
    58       val m = gcd (absp, q)
    59       in Rat(a = (0 <= p), absp div m, q div m) end;
    59     in Rat(a = (IntInf.fromInt 0 <= p), absp div m, q div m) end;
    60 
    60 
    61 fun common (p1, q1, p2, q2) =
    61 fun common (p1, q1, p2, q2) =
    62   let val q' = lcm (q1, q2)
    62   let val q' = lcm (q1, q2)
    63   in (p1 * (q' div q1), p2 * (q' div q2), q') end
    63   in (p1 * (q' div q1), p2 * (q' div q2), q') end
    64 
    64 
    65 fun rat_of_quotient (p, 0) =
    65 fun rat_of_quotient (p, q) =
    66       raise DIVZERO
    66   if q = IntInf.fromInt 0 then raise DIVZERO
    67   | rat_of_quotient (p, q) =
    67   else norm (IntInf.fromInt 0 <= q, p, abs q);
    68       norm (0 <= q, p, abs q);
       
    69 
    68 
    70 fun quotient_of_rat (Rat (a, p, q)) = (if a then p else ~p, q);
    69 fun quotient_of_rat (Rat (a, p, q)) = (if a then p else ~p, q);
    71 
    70 
    72 fun string_of_rat r =
    71 fun string_of_rat r =
    73   let val (p, q) = quotient_of_rat r
    72   let val (p, q) = quotient_of_rat r
   102   in norm (true, num, den) end;
   101   in norm (true, num, den) end;
   103 
   102 
   104 fun mult (Rat (a1, p1, q1), Rat (a2, p2, q2)) =
   103 fun mult (Rat (a1, p1, q1), Rat (a2, p2, q2)) =
   105   norm (a1=a2, p1*p2, q1*q2);
   104   norm (a1=a2, p1*p2, q1*q2);
   106 
   105 
   107 fun neg (r as Rat (_, 0, _)) = r
   106 fun neg (r as Rat (b, p, q)) =
   108   | neg (Rat (b, p, q)) =
   107   if p = IntInf.fromInt 0 then r
   109       Rat (not b, p, q);
   108   else Rat (not b, p, q);
   110 
   109 
   111 fun inv (Rat (a, 0, q)) =
   110 fun inv (Rat (a, p, q)) =
   112       raise DIVZERO
   111   if p = IntInf.fromInt 0 then raise DIVZERO
   113   | inv (Rat (a, p, q)) =
   112   else Rat (a, q, p);
   114       Rat (a, q, p)
       
   115 
   113 
   116 fun ge0 (Rat (a, _, _)) = a;
   114 fun ge0 (Rat (a, _, _)) = a;
   117 fun gt0 (Rat (a, p, _)) = a andalso p > 0;
   115 fun gt0 (Rat (a, p, _)) = a andalso p > IntInf.fromInt 0;
   118 
   116 
   119 fun roundup (r as Rat (_, _, 1)) = r
   117 fun roundup (r as Rat (a, p, q)) =
   120   | roundup (Rat (a, p, q)) =
   118   if q = IntInf.fromInt 1 then r
   121       let
   119   else
   122         fun round true q = Rat (true, q+1, 1)
   120     let
   123           | round false 0 = Rat (true, 0 ,1)
   121       fun round true q = Rat (true, q + IntInf.fromInt 1, IntInf.fromInt 1)
   124           | round false q = Rat (false, q, 1)
   122         | round false q =
   125       in round a (p div q) end;
   123             if q = IntInf.fromInt 0
       
   124             then Rat (true, IntInf.fromInt 0, IntInf.fromInt 1)
       
   125             else Rat (false, q, IntInf.fromInt 1);
       
   126     in round a (p div q) end;
   126 
   127 
   127 fun rounddown (r as Rat (_, _, 1)) = r
   128 fun rounddown (r as Rat (a, p, q)) =
   128   | rounddown (Rat (a, p, q)) =
   129   if q = IntInf.fromInt 1 then r
   129       let
   130   else
   130         fun round true q = Rat (true, q, 1)
   131     let
   131           | round false q = Rat (false, q+1, 1)
   132       fun round true q = Rat (true, q, IntInf.fromInt 1)
   132       in round a (p div q) end;
   133         | round false q = Rat (false, q + IntInf.fromInt 1, IntInf.fromInt 1)
       
   134     in round a (p div q) end;
   133 
   135 
   134 end;
   136 end;