haftmann@24584: (* Title: Tools/rat.ML haftmann@23520: Author: Tobias Nipkow, Florian Haftmann, TU Muenchen haftmann@23251: haftmann@23251: Canonical implementation of exact rational numbers. haftmann@23251: *) haftmann@23251: haftmann@23251: signature RAT = haftmann@23251: sig wenzelm@23297: eqtype rat haftmann@23251: exception DIVZERO haftmann@23251: val zero: rat haftmann@23251: val one: rat haftmann@23251: val two: rat wenzelm@24630: val rat_of_int: int -> rat wenzelm@24630: val rat_of_quotient: int * int -> rat wenzelm@24630: val quotient_of_rat: rat -> int * int haftmann@23251: val string_of_rat: rat -> string haftmann@23251: val eq: rat * rat -> bool haftmann@23520: val ord: rat * rat -> order haftmann@23251: val le: rat -> rat -> bool haftmann@23251: val lt: rat -> rat -> bool haftmann@23520: val sign: rat -> order haftmann@23520: val abs: rat -> rat haftmann@23251: val add: rat -> rat -> rat haftmann@23251: val mult: rat -> rat -> rat haftmann@23251: val neg: rat -> rat haftmann@23251: val inv: rat -> rat haftmann@23520: val rounddown: rat -> rat haftmann@23251: val roundup: rat -> rat haftmann@23251: end; haftmann@23251: haftmann@23251: structure Rat : RAT = haftmann@23251: struct haftmann@23251: haftmann@23520: fun common (p1, q1) (p2, q2) = haftmann@23520: let haftmann@23520: val m = Integer.lcm q1 q2; wenzelm@24630: in ((p1 * (m div q1), p2 * (m div q2)), m) end; haftmann@23520: wenzelm@24630: datatype rat = Rat of int * int; (*nominator, denominator (positive!)*) haftmann@23251: haftmann@23251: exception DIVZERO; haftmann@23251: haftmann@23251: fun rat_of_quotient (p, q) = haftmann@23261: let wenzelm@24630: val m = Integer.gcd (Int.abs p) q wenzelm@24630: in Rat (p div m, q div m) end handle Div => raise DIVZERO; haftmann@23520: haftmann@23520: fun quotient_of_rat (Rat r) = r; haftmann@23520: haftmann@23520: fun rat_of_int i = Rat (i, 1); haftmann@23251: haftmann@23520: val zero = rat_of_int 0; haftmann@23520: val one = rat_of_int 1; haftmann@23520: val two = rat_of_int 2; haftmann@23251: haftmann@23520: fun string_of_rat (Rat (p, q)) = wenzelm@24630: string_of_int p ^ "/" ^ string_of_int q; haftmann@23520: haftmann@23520: fun eq (Rat (p1, q1), Rat (p2, q2)) = (p1 = p2 andalso q1 = q2); haftmann@23251: wenzelm@24630: fun ord (Rat (p1, q1), Rat (p2, q2)) = wenzelm@24630: case (Integer.sign p1, Integer.sign p2) haftmann@23520: of (LESS, EQUAL) => LESS haftmann@23520: | (LESS, GREATER) => LESS haftmann@23520: | (EQUAL, LESS) => GREATER haftmann@23520: | (EQUAL, EQUAL) => EQUAL haftmann@23520: | (EQUAL, GREATER) => LESS haftmann@23520: | (GREATER, LESS) => GREATER haftmann@23520: | (GREATER, EQUAL) => GREATER wenzelm@24630: | _ => int_ord (fst (common (p1, q1) (p2, q2))); haftmann@23251: haftmann@23520: fun le a b = not (ord (a, b) = GREATER); haftmann@23520: fun lt a b = (ord (a, b) = LESS); haftmann@23251: haftmann@23520: fun sign (Rat (p, _)) = Integer.sign p; haftmann@23251: wenzelm@24630: fun abs (Rat (p, q)) = Rat (Int.abs p, q); haftmann@23251: haftmann@23520: fun add (Rat (p1, q1)) (Rat (p2, q2)) = haftmann@23520: let haftmann@23520: val ((m1, m2), n) = common (p1, q1) (p2, q2); wenzelm@24630: in rat_of_quotient (m1 + m2, n) end; haftmann@23251: haftmann@23520: fun mult (Rat (p1, q1)) (Rat (p2, q2)) = wenzelm@24630: rat_of_quotient (p1 * p2, q1 * q2); wenzelm@24630: wenzelm@24630: fun neg (Rat (p, q)) = Rat (~ p, q); haftmann@23251: wenzelm@24630: fun inv (Rat (p, q)) = wenzelm@24630: case Integer.sign p wenzelm@24630: of LESS => Rat (~ q, ~ p) haftmann@24522: | EQUAL => raise DIVZERO haftmann@24521: | GREATER => Rat (q, p); haftmann@23251: wenzelm@24630: fun rounddown (Rat (p, q)) = Rat (p div q, 1); haftmann@23520: wenzelm@24630: fun roundup (Rat (p, q)) = wenzelm@24630: case Integer.div_mod p q haftmann@23520: of (m, 0) => Rat (m, 1) haftmann@23520: | (m, _) => Rat (m + 1, 1); haftmann@23251: haftmann@23251: end; haftmann@23251: haftmann@23261: infix 7 */ //; wenzelm@23297: infix 6 +/ -/; haftmann@23251: infix 4 =/ / >=/ <>/; haftmann@23251: haftmann@23251: fun a +/ b = Rat.add a b; haftmann@23251: fun a -/ b = a +/ Rat.neg b; haftmann@23251: fun a */ b = Rat.mult a b; wenzelm@23297: fun a // b = a */ Rat.inv b; haftmann@23261: fun a =/ b = Rat.eq (a, b); haftmann@23251: fun a / b = b =/ b = b <=/ a; haftmann@23251: fun a <>/ b = not (a =/ b);