23251

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

23261

15 
val rat_of_int: integer > rat


16 
val rat_of_quotient: integer * integer > rat


17 
val quotient_of_rat: rat > integer * integer

23251

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 

23261

35 
datatype rat = Rat of bool * integer * integer;

23251

36 


37 
exception DIVZERO;


38 

23261

39 
val zero = Rat (true, Integer.zero, Integer.one);


40 
val one = Rat (true, Integer.one, Integer.one);


41 
val two = Rat (true, Integer.two, Integer.one);

23251

42 


43 
fun rat_of_int i =

23261

44 
let


45 
val (a, p) = Integer.signabs i


46 
in Rat (a, p, Integer.one) end;

23251

47 


48 
fun norm (a, p, q) =

23261

49 
if Integer.cmp_zero p = EQUAL then Rat (true, Integer.zero, Integer.one)

23251

50 
else


51 
let

23261

52 
val (b, absp) = Integer.signabs p;


53 
val m = Integer.gcd absp q;


54 
in Rat (a = b, Integer.div absp m, Integer.div q m) end;

23251

55 


56 
fun common (p1, q1, p2, q2) =

23261

57 
let


58 
val q' = Integer.lcm q1 q2;


59 
in (p1 *% (Integer.div q' q1), p2 *% (Integer.div q' q2), q') end

23251

60 


61 
fun rat_of_quotient (p, q) =

23261

62 
let


63 
val (a, absq) = Integer.signabs q;


64 
in


65 
if Integer.cmp_zero absq = EQUAL then raise DIVZERO


66 
else norm (a, p, absq)


67 
end;

23251

68 

23261

69 
fun quotient_of_rat (Rat (a, p, q)) = (if a then p else Integer.neg p, q);

23251

70 


71 
fun string_of_rat r =

23261

72 
let


73 
val (p, q) = quotient_of_rat r;


74 
in Integer.string_of_int p ^ "/" ^ Integer.string_of_int q end;

23251

75 


76 
fun eq (Rat (false, _, _), Rat (true, _, _)) = false


77 
 eq (Rat (true, _, _), Rat (false, _, _)) = false

23261

78 
 eq (Rat (_, p1, q1), Rat (_, p2, q2)) = p1 =% p2 andalso q1 =% q2;

23251

79 


80 
fun cmp (Rat (false, _, _), Rat (true, _, _)) = LESS


81 
 cmp (Rat (true, _, _), Rat (false, _, _)) = GREATER


82 
 cmp (Rat (a, p1, q1), Rat (_, p2, q2)) =


83 
let val (r1, r2, _) = common (p1, q1, p2, q2)

23261

84 
in if a then Integer.cmp (r1, r2) else Integer.cmp (r2, r1) end;

23251

85 


86 
fun le a b = let val order = cmp (a, b) in order = LESS orelse order = EQUAL end;

23261

87 
fun lt a b = (cmp (a, b) = LESS);

23251

88 


89 
fun cmp_zero (Rat (false, _, _)) = LESS


90 
 cmp_zero (Rat (_, 0, _)) = EQUAL


91 
 cmp_zero (Rat (_, _, _)) = GREATER;


92 


93 
fun add (Rat (a1, p1, q1)) (Rat(a2, p2, q2)) =


94 
let

23261

95 
val (r1, r2, den) = common (p1, q1, p2, q2);


96 
val num = (if a1 then r1 else Integer.neg r1)


97 
+% (if a2 then r2 else Integer.neg r2);

23251

98 
in norm (true, num, den) end;


99 


100 
fun mult (Rat (a1, p1, q1)) (Rat (a2, p2, q2)) =

23261

101 
norm (a1 = a2, p1 *% p2, q1 *% q2);

23251

102 


103 
fun neg (r as Rat (b, p, q)) =

23261

104 
if Integer.cmp_zero p = EQUAL then r

23251

105 
else Rat (not b, p, q);


106 


107 
fun inv (Rat (a, p, q)) =

23261

108 
if Integer.cmp_zero q = EQUAL then raise DIVZERO

23251

109 
else Rat (a, q, p);


110 


111 
fun roundup (r as Rat (a, p, q)) =

23261

112 
if q = Integer.one then r

23251

113 
else


114 
let

23261

115 
fun round true q = Rat (true, Integer.inc q, Integer.one)

23251

116 
 round false q =

23261

117 
Rat (Integer.cmp_zero q = EQUAL, Integer.int 0, Integer.int 1);


118 
in round a (Integer.div p q) end;

23251

119 


120 
fun rounddown (r as Rat (a, p, q)) =

23261

121 
if q = Integer.one then r

23251

122 
else


123 
let

23261

124 
fun round true q = Rat (true, q, Integer.one)


125 
 round false q = Rat (false, Integer.inc q, Integer.one)


126 
in round a (Integer.div p q) end;

23251

127 


128 
end;


129 

23261

130 
infix 7 */ //;


131 
infix 6 +/ /;

23251

132 
infix 4 =/ </ <=/ >/ >=/ <>/;


133 


134 
fun a +/ b = Rat.add a b;


135 
fun a / b = a +/ Rat.neg b;


136 
fun a */ b = Rat.mult a b;


137 
fun a // b = a */ Rat.inv b;

23261

138 
fun a =/ b = Rat.eq (a, b);

23251

139 
fun a </ b = Rat.lt a b;


140 
fun a <=/ b = Rat.le a b;


141 
fun a >/ b = b </ a;


142 
fun a >=/ b = b <=/ a;


143 
fun a <>/ b = not (a =/ b);
