src/Pure/General/rat.ML
author haftmann
Fri, 21 Oct 2005 08:23:45 +0200
changeset 17940 3706c254d296
parent 17848 de5d9d5e99f5
child 17950 924d3e71cdc9
permissions -rw-r--r--
added rounding functions
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
17848
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
     1
(*  Title:      Pure/General/rat.ML
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
     2
    ID:         $Id$
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
     3
    Author:     Tobias Nipkow, TU Muenchen
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
     4
17940
3706c254d296 added rounding functions
haftmann
parents: 17848
diff changeset
     5
Canonical implementation of exact rational numbers.
17848
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
     6
*)
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
     7
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
     8
signature RAT =
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
     9
sig
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    10
  type rat
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    11
  exception DIVZERO
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    12
  val zero: rat
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    13
  val rat_of_int: int -> rat
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    14
  val rat_of_intinf: IntInf.int -> rat
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    15
  val rat_of_quotient: IntInf.int * IntInf.int -> rat
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    16
  val quotient_of_rat: rat -> IntInf.int * IntInf.int
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    17
  val string_of_rat: rat -> string
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    18
  val eq: rat * rat -> bool
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    19
  val le: rat * rat -> bool
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    20
  val lt: rat * rat -> bool
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    21
  val ord: rat * rat -> order
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    22
  val add: rat * rat -> rat
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    23
  val mult: rat * rat -> rat
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    24
  val neg: rat -> rat
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    25
  val inv: rat -> rat
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    26
  val ge0: rat -> bool
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    27
  val gt0: rat -> bool
17940
3706c254d296 added rounding functions
haftmann
parents: 17848
diff changeset
    28
  val roundup: rat -> rat
3706c254d296 added rounding functions
haftmann
parents: 17848
diff changeset
    29
  val rounddown: rat -> rat
17848
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    30
end;
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    31
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    32
structure Rat: RAT =
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    33
struct
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    34
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    35
(*keep them normalized!*)
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    36
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    37
datatype rat = Rat of bool * IntInf.int * IntInf.int;
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    38
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    39
exception DIVZERO;
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    40
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    41
val zero = Rat (true, 0, 1);
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    42
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    43
fun rat_of_intinf i =
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    44
  if i < 0
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    45
  then Rat (false, ~i, 1)
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    46
  else Rat (true, i, 1);
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    47
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    48
fun rat_of_int i = rat_of_intinf (IntInf.fromInt i);
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    49
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    50
fun norm (a, 0, q) =
17940
3706c254d296 added rounding functions
haftmann
parents: 17848
diff changeset
    51
      Rat (true, 0, 1) (*is that intentional?*)
17848
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    52
  | norm (a, p, q) =
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    53
      let
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    54
        val absp = abs p
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    55
        val m = gcd (absp, q)
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    56
      in Rat(a = (0 <= p), absp div m, q div m) end;
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    57
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    58
fun common (p1, q1, p2, q2) =
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    59
  let val q' = lcm (q1, q2)
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    60
  in (p1 * (q' div q1), p2 * (q' div q2), q') end
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    61
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    62
fun rat_of_quotient (p, 0) =
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    63
      raise DIVZERO
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    64
  | rat_of_quotient (p, q) =
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    65
      norm (0 <= q, p, abs q);
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    66
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    67
fun quotient_of_rat (Rat (a, p, q)) = (if a then p else ~p, q);
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    68
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    69
fun string_of_rat r =
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    70
  let val (p, q) = quotient_of_rat r
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    71
  in IntInf.toString p ^ "/" ^ IntInf.toString q end;
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    72
17940
3706c254d296 added rounding functions
haftmann
parents: 17848
diff changeset
    73
fun eq (Rat (false, _, _), Rat (true, _, _)) = false
3706c254d296 added rounding functions
haftmann
parents: 17848
diff changeset
    74
  | eq (Rat (true, _, _), Rat (false, _, _)) = false
3706c254d296 added rounding functions
haftmann
parents: 17848
diff changeset
    75
  | eq (Rat (_, p1, q1), Rat (_, p2, q2)) = p1 = p2 andalso q1 = q2
3706c254d296 added rounding functions
haftmann
parents: 17848
diff changeset
    76
3706c254d296 added rounding functions
haftmann
parents: 17848
diff changeset
    77
fun le (Rat (false, _, _), Rat (true, _, _)) = true
3706c254d296 added rounding functions
haftmann
parents: 17848
diff changeset
    78
  | le (Rat (true, _, _), Rat (false, _, _)) = false
3706c254d296 added rounding functions
haftmann
parents: 17848
diff changeset
    79
  | le (Rat (a, p1, q1), Rat (_, p2, q2)) =
3706c254d296 added rounding functions
haftmann
parents: 17848
diff changeset
    80
      let val (r1, r2, _) = common (p1, q1, p2, q2)
3706c254d296 added rounding functions
haftmann
parents: 17848
diff changeset
    81
      in if a then r1 <= r2 else r2 <= r1 end;
3706c254d296 added rounding functions
haftmann
parents: 17848
diff changeset
    82
3706c254d296 added rounding functions
haftmann
parents: 17848
diff changeset
    83
fun lt (Rat (false, _, _), Rat (true, _, _)) = true
3706c254d296 added rounding functions
haftmann
parents: 17848
diff changeset
    84
  | lt (Rat (true, _, _), Rat (false, _, _)) = false
3706c254d296 added rounding functions
haftmann
parents: 17848
diff changeset
    85
  | lt (Rat (a, p1, q1), Rat (_, p2, q2)) =
3706c254d296 added rounding functions
haftmann
parents: 17848
diff changeset
    86
      let val (r1, r2, _) = common (p1, q1, p2, q2)
3706c254d296 added rounding functions
haftmann
parents: 17848
diff changeset
    87
      in if a then r1 <= r2 else r2 <= r1 end;
3706c254d296 added rounding functions
haftmann
parents: 17848
diff changeset
    88
17848
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    89
fun ord (Rat (false, _, _), Rat (true, _, _)) = LESS
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    90
  | ord (Rat (true, _, _), Rat (false, _, _)) = GREATER
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    91
  | ord (Rat (a, p1, q1), Rat (_, p2, q2)) =
17940
3706c254d296 added rounding functions
haftmann
parents: 17848
diff changeset
    92
      let val (r1, r2, _) = common (p1, q1, p2, q2)
17848
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    93
      in if a then IntInf.compare (r1, r2) else IntInf.compare (r2, r1) end;
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    94
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    95
fun add (Rat (a1, p1, q1), Rat(a2, p2, q2)) =
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    96
  let
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    97
    val (r1, r2, den) = common (p1, q1, p2, q2)
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    98
    val num = (if a1 then r1 else ~r1) + (if a2 then r2 else ~r2)
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
    99
  in norm (true, num, den) end;
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
   100
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
   101
fun mult (Rat (a1, p1, q1), Rat (a2, p2, q2)) =
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
   102
  norm (a1=a2, p1*p2, q1*q2);
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
   103
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
   104
fun neg (r as Rat (_, 0, _)) = r
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
   105
  | neg (Rat (b, p, q)) =
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
   106
      Rat (not b, p, q);
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
   107
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
   108
fun inv (Rat (a, 0, q)) =
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
   109
      raise DIVZERO
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
   110
  | inv (Rat (a, p, q)) =
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
   111
      Rat (a, q, p)
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
   112
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
   113
fun ge0 (Rat (a, _, _)) = a;
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
   114
fun gt0 (Rat (a, p, _)) = a andalso p > 0;
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
   115
17940
3706c254d296 added rounding functions
haftmann
parents: 17848
diff changeset
   116
fun roundup (r as Rat (_, _, 1)) = r
3706c254d296 added rounding functions
haftmann
parents: 17848
diff changeset
   117
  | roundup (Rat (a, p, q)) =
3706c254d296 added rounding functions
haftmann
parents: 17848
diff changeset
   118
      let
3706c254d296 added rounding functions
haftmann
parents: 17848
diff changeset
   119
        fun round true q = Rat (true, q+1, 1)
3706c254d296 added rounding functions
haftmann
parents: 17848
diff changeset
   120
          | round false 0 = Rat (true, 0 ,1)
3706c254d296 added rounding functions
haftmann
parents: 17848
diff changeset
   121
          | round false q = Rat (false, q, 1)
3706c254d296 added rounding functions
haftmann
parents: 17848
diff changeset
   122
      in round a (p div q) end;
3706c254d296 added rounding functions
haftmann
parents: 17848
diff changeset
   123
3706c254d296 added rounding functions
haftmann
parents: 17848
diff changeset
   124
fun rounddown (r as Rat (_, _, 1)) = r
3706c254d296 added rounding functions
haftmann
parents: 17848
diff changeset
   125
  | rounddown (Rat (a, p, q)) =
3706c254d296 added rounding functions
haftmann
parents: 17848
diff changeset
   126
      let
3706c254d296 added rounding functions
haftmann
parents: 17848
diff changeset
   127
        fun round true q = Rat (true, q, 1)
3706c254d296 added rounding functions
haftmann
parents: 17848
diff changeset
   128
          | round false q = Rat (false, q+1, 1)
3706c254d296 added rounding functions
haftmann
parents: 17848
diff changeset
   129
      in round a (p div q) end;
3706c254d296 added rounding functions
haftmann
parents: 17848
diff changeset
   130
17848
de5d9d5e99f5 added module rat.ML for rational numbers
haftmann
parents:
diff changeset
   131
end;