Guido van Rossum | 0609f19 | 1997-05-13 19:25:57 +0000 | [diff] [blame] | 1 | '''\ |
| 2 | This module implements rational numbers. |
| 3 | |
| 4 | The entry point of this module is the function |
Andrew M. Kuchling | 946c53e | 2003-04-24 17:13:18 +0000 | [diff] [blame] | 5 | rat(numerator, denominator) |
Guido van Rossum | 0609f19 | 1997-05-13 19:25:57 +0000 | [diff] [blame] | 6 | If either numerator or denominator is of an integral or rational type, |
| 7 | the result is a rational number, else, the result is the simplest of |
| 8 | the types float and complex which can hold numerator/denominator. |
| 9 | If denominator is omitted, it defaults to 1. |
| 10 | Rational numbers can be used in calculations with any other numeric |
| 11 | type. The result of the calculation will be rational if possible. |
| 12 | |
| 13 | There is also a test function with calling sequence |
Andrew M. Kuchling | 946c53e | 2003-04-24 17:13:18 +0000 | [diff] [blame] | 14 | test() |
Guido van Rossum | 0609f19 | 1997-05-13 19:25:57 +0000 | [diff] [blame] | 15 | The documentation string of the test function contains the expected |
| 16 | output. |
| 17 | ''' |
| 18 | |
| 19 | # Contributed by Sjoerd Mullender |
Guido van Rossum | e876949 | 1992-08-13 12:14:11 +0000 | [diff] [blame] | 20 | |
Guido van Rossum | 2e61103 | 1994-10-09 22:36:28 +0000 | [diff] [blame] | 21 | from types import * |
Guido van Rossum | e876949 | 1992-08-13 12:14:11 +0000 | [diff] [blame] | 22 | |
Guido van Rossum | e876949 | 1992-08-13 12:14:11 +0000 | [diff] [blame] | 23 | def gcd(a, b): |
Andrew M. Kuchling | 946c53e | 2003-04-24 17:13:18 +0000 | [diff] [blame] | 24 | '''Calculate the Greatest Common Divisor.''' |
| 25 | while b: |
| 26 | a, b = b, a%b |
| 27 | return a |
Guido van Rossum | e876949 | 1992-08-13 12:14:11 +0000 | [diff] [blame] | 28 | |
Guido van Rossum | 0609f19 | 1997-05-13 19:25:57 +0000 | [diff] [blame] | 29 | def rat(num, den = 1): |
Andrew M. Kuchling | 946c53e | 2003-04-24 17:13:18 +0000 | [diff] [blame] | 30 | # must check complex before float |
| 31 | if isinstance(num, complex) or isinstance(den, complex): |
| 32 | # numerator or denominator is complex: return a complex |
| 33 | return complex(num) / complex(den) |
| 34 | if isinstance(num, float) or isinstance(den, float): |
| 35 | # numerator or denominator is float: return a float |
| 36 | return float(num) / float(den) |
| 37 | # otherwise return a rational |
| 38 | return Rat(num, den) |
Guido van Rossum | e876949 | 1992-08-13 12:14:11 +0000 | [diff] [blame] | 39 | |
| 40 | class Rat: |
Andrew M. Kuchling | 946c53e | 2003-04-24 17:13:18 +0000 | [diff] [blame] | 41 | '''This class implements rational numbers.''' |
Guido van Rossum | e876949 | 1992-08-13 12:14:11 +0000 | [diff] [blame] | 42 | |
Andrew M. Kuchling | 946c53e | 2003-04-24 17:13:18 +0000 | [diff] [blame] | 43 | def __init__(self, num, den = 1): |
| 44 | if den == 0: |
| 45 | raise ZeroDivisionError, 'rat(x, 0)' |
Guido van Rossum | 0609f19 | 1997-05-13 19:25:57 +0000 | [diff] [blame] | 46 | |
Andrew M. Kuchling | 946c53e | 2003-04-24 17:13:18 +0000 | [diff] [blame] | 47 | # normalize |
Guido van Rossum | 0609f19 | 1997-05-13 19:25:57 +0000 | [diff] [blame] | 48 | |
Andrew M. Kuchling | 946c53e | 2003-04-24 17:13:18 +0000 | [diff] [blame] | 49 | # must check complex before float |
| 50 | if (isinstance(num, complex) or |
| 51 | isinstance(den, complex)): |
| 52 | # numerator or denominator is complex: |
| 53 | # normalized form has denominator == 1+0j |
| 54 | self.__num = complex(num) / complex(den) |
| 55 | self.__den = complex(1) |
| 56 | return |
| 57 | if isinstance(num, float) or isinstance(den, float): |
| 58 | # numerator or denominator is float: |
| 59 | # normalized form has denominator == 1.0 |
| 60 | self.__num = float(num) / float(den) |
| 61 | self.__den = 1.0 |
| 62 | return |
| 63 | if (isinstance(num, self.__class__) or |
| 64 | isinstance(den, self.__class__)): |
| 65 | # numerator or denominator is rational |
| 66 | new = num / den |
| 67 | if not isinstance(new, self.__class__): |
| 68 | self.__num = new |
| 69 | if isinstance(new, complex): |
| 70 | self.__den = complex(1) |
| 71 | else: |
| 72 | self.__den = 1.0 |
| 73 | else: |
| 74 | self.__num = new.__num |
| 75 | self.__den = new.__den |
| 76 | else: |
| 77 | # make sure numerator and denominator don't |
| 78 | # have common factors |
| 79 | # this also makes sure that denominator > 0 |
| 80 | g = gcd(num, den) |
| 81 | self.__num = num / g |
| 82 | self.__den = den / g |
| 83 | # try making numerator and denominator of IntType if they fit |
| 84 | try: |
| 85 | numi = int(self.__num) |
| 86 | deni = int(self.__den) |
| 87 | except (OverflowError, TypeError): |
| 88 | pass |
| 89 | else: |
| 90 | if self.__num == numi and self.__den == deni: |
| 91 | self.__num = numi |
| 92 | self.__den = deni |
Guido van Rossum | e876949 | 1992-08-13 12:14:11 +0000 | [diff] [blame] | 93 | |
Andrew M. Kuchling | 946c53e | 2003-04-24 17:13:18 +0000 | [diff] [blame] | 94 | def __repr__(self): |
| 95 | return 'Rat(%s,%s)' % (self.__num, self.__den) |
Guido van Rossum | 2e61103 | 1994-10-09 22:36:28 +0000 | [diff] [blame] | 96 | |
Andrew M. Kuchling | 946c53e | 2003-04-24 17:13:18 +0000 | [diff] [blame] | 97 | def __str__(self): |
| 98 | if self.__den == 1: |
| 99 | return str(self.__num) |
| 100 | else: |
| 101 | return '(%s/%s)' % (str(self.__num), str(self.__den)) |
Guido van Rossum | e876949 | 1992-08-13 12:14:11 +0000 | [diff] [blame] | 102 | |
Andrew M. Kuchling | 946c53e | 2003-04-24 17:13:18 +0000 | [diff] [blame] | 103 | # a + b |
| 104 | def __add__(a, b): |
| 105 | try: |
| 106 | return rat(a.__num * b.__den + b.__num * a.__den, |
| 107 | a.__den * b.__den) |
| 108 | except OverflowError: |
| 109 | return rat(long(a.__num) * long(b.__den) + |
| 110 | long(b.__num) * long(a.__den), |
| 111 | long(a.__den) * long(b.__den)) |
Guido van Rossum | e876949 | 1992-08-13 12:14:11 +0000 | [diff] [blame] | 112 | |
Andrew M. Kuchling | 946c53e | 2003-04-24 17:13:18 +0000 | [diff] [blame] | 113 | def __radd__(b, a): |
| 114 | return Rat(a) + b |
Guido van Rossum | 0609f19 | 1997-05-13 19:25:57 +0000 | [diff] [blame] | 115 | |
Andrew M. Kuchling | 946c53e | 2003-04-24 17:13:18 +0000 | [diff] [blame] | 116 | # a - b |
| 117 | def __sub__(a, b): |
| 118 | try: |
| 119 | return rat(a.__num * b.__den - b.__num * a.__den, |
| 120 | a.__den * b.__den) |
| 121 | except OverflowError: |
| 122 | return rat(long(a.__num) * long(b.__den) - |
| 123 | long(b.__num) * long(a.__den), |
| 124 | long(a.__den) * long(b.__den)) |
Guido van Rossum | e876949 | 1992-08-13 12:14:11 +0000 | [diff] [blame] | 125 | |
Andrew M. Kuchling | 946c53e | 2003-04-24 17:13:18 +0000 | [diff] [blame] | 126 | def __rsub__(b, a): |
| 127 | return Rat(a) - b |
Guido van Rossum | 0609f19 | 1997-05-13 19:25:57 +0000 | [diff] [blame] | 128 | |
Andrew M. Kuchling | 946c53e | 2003-04-24 17:13:18 +0000 | [diff] [blame] | 129 | # a * b |
| 130 | def __mul__(a, b): |
| 131 | try: |
| 132 | return rat(a.__num * b.__num, a.__den * b.__den) |
| 133 | except OverflowError: |
| 134 | return rat(long(a.__num) * long(b.__num), |
| 135 | long(a.__den) * long(b.__den)) |
Guido van Rossum | e876949 | 1992-08-13 12:14:11 +0000 | [diff] [blame] | 136 | |
Andrew M. Kuchling | 946c53e | 2003-04-24 17:13:18 +0000 | [diff] [blame] | 137 | def __rmul__(b, a): |
| 138 | return Rat(a) * b |
Guido van Rossum | 0609f19 | 1997-05-13 19:25:57 +0000 | [diff] [blame] | 139 | |
Andrew M. Kuchling | 946c53e | 2003-04-24 17:13:18 +0000 | [diff] [blame] | 140 | # a / b |
| 141 | def __div__(a, b): |
| 142 | try: |
| 143 | return rat(a.__num * b.__den, a.__den * b.__num) |
| 144 | except OverflowError: |
| 145 | return rat(long(a.__num) * long(b.__den), |
| 146 | long(a.__den) * long(b.__num)) |
Guido van Rossum | e876949 | 1992-08-13 12:14:11 +0000 | [diff] [blame] | 147 | |
Andrew M. Kuchling | 946c53e | 2003-04-24 17:13:18 +0000 | [diff] [blame] | 148 | def __rdiv__(b, a): |
| 149 | return Rat(a) / b |
Guido van Rossum | e876949 | 1992-08-13 12:14:11 +0000 | [diff] [blame] | 150 | |
Andrew M. Kuchling | 946c53e | 2003-04-24 17:13:18 +0000 | [diff] [blame] | 151 | # a % b |
| 152 | def __mod__(a, b): |
| 153 | div = a / b |
| 154 | try: |
| 155 | div = int(div) |
| 156 | except OverflowError: |
| 157 | div = long(div) |
| 158 | return a - b * div |
Guido van Rossum | 0609f19 | 1997-05-13 19:25:57 +0000 | [diff] [blame] | 159 | |
Andrew M. Kuchling | 946c53e | 2003-04-24 17:13:18 +0000 | [diff] [blame] | 160 | def __rmod__(b, a): |
| 161 | return Rat(a) % b |
Guido van Rossum | 0609f19 | 1997-05-13 19:25:57 +0000 | [diff] [blame] | 162 | |
Andrew M. Kuchling | 946c53e | 2003-04-24 17:13:18 +0000 | [diff] [blame] | 163 | # a ** b |
| 164 | def __pow__(a, b): |
| 165 | if b.__den != 1: |
| 166 | if isinstance(a.__num, complex): |
| 167 | a = complex(a) |
| 168 | else: |
| 169 | a = float(a) |
| 170 | if isinstance(b.__num, complex): |
| 171 | b = complex(b) |
| 172 | else: |
| 173 | b = float(b) |
| 174 | return a ** b |
| 175 | try: |
| 176 | return rat(a.__num ** b.__num, a.__den ** b.__num) |
| 177 | except OverflowError: |
| 178 | return rat(long(a.__num) ** b.__num, |
| 179 | long(a.__den) ** b.__num) |
Guido van Rossum | 0609f19 | 1997-05-13 19:25:57 +0000 | [diff] [blame] | 180 | |
Andrew M. Kuchling | 946c53e | 2003-04-24 17:13:18 +0000 | [diff] [blame] | 181 | def __rpow__(b, a): |
| 182 | return Rat(a) ** b |
Guido van Rossum | 0609f19 | 1997-05-13 19:25:57 +0000 | [diff] [blame] | 183 | |
Andrew M. Kuchling | 946c53e | 2003-04-24 17:13:18 +0000 | [diff] [blame] | 184 | # -a |
| 185 | def __neg__(a): |
| 186 | try: |
| 187 | return rat(-a.__num, a.__den) |
| 188 | except OverflowError: |
| 189 | # a.__num == sys.maxint |
| 190 | return rat(-long(a.__num), a.__den) |
Guido van Rossum | 0609f19 | 1997-05-13 19:25:57 +0000 | [diff] [blame] | 191 | |
Andrew M. Kuchling | 946c53e | 2003-04-24 17:13:18 +0000 | [diff] [blame] | 192 | # abs(a) |
| 193 | def __abs__(a): |
| 194 | return rat(abs(a.__num), a.__den) |
Guido van Rossum | 0609f19 | 1997-05-13 19:25:57 +0000 | [diff] [blame] | 195 | |
Andrew M. Kuchling | 946c53e | 2003-04-24 17:13:18 +0000 | [diff] [blame] | 196 | # int(a) |
| 197 | def __int__(a): |
| 198 | return int(a.__num / a.__den) |
Guido van Rossum | 0609f19 | 1997-05-13 19:25:57 +0000 | [diff] [blame] | 199 | |
Andrew M. Kuchling | 946c53e | 2003-04-24 17:13:18 +0000 | [diff] [blame] | 200 | # long(a) |
| 201 | def __long__(a): |
| 202 | return long(a.__num) / long(a.__den) |
Guido van Rossum | 0609f19 | 1997-05-13 19:25:57 +0000 | [diff] [blame] | 203 | |
Andrew M. Kuchling | 946c53e | 2003-04-24 17:13:18 +0000 | [diff] [blame] | 204 | # float(a) |
| 205 | def __float__(a): |
| 206 | return float(a.__num) / float(a.__den) |
Guido van Rossum | 0609f19 | 1997-05-13 19:25:57 +0000 | [diff] [blame] | 207 | |
Andrew M. Kuchling | 946c53e | 2003-04-24 17:13:18 +0000 | [diff] [blame] | 208 | # complex(a) |
| 209 | def __complex__(a): |
| 210 | return complex(a.__num) / complex(a.__den) |
Guido van Rossum | 0609f19 | 1997-05-13 19:25:57 +0000 | [diff] [blame] | 211 | |
Andrew M. Kuchling | 946c53e | 2003-04-24 17:13:18 +0000 | [diff] [blame] | 212 | # cmp(a,b) |
| 213 | def __cmp__(a, b): |
| 214 | diff = Rat(a - b) |
| 215 | if diff.__num < 0: |
| 216 | return -1 |
| 217 | elif diff.__num > 0: |
| 218 | return 1 |
| 219 | else: |
| 220 | return 0 |
Guido van Rossum | 0609f19 | 1997-05-13 19:25:57 +0000 | [diff] [blame] | 221 | |
Andrew M. Kuchling | 946c53e | 2003-04-24 17:13:18 +0000 | [diff] [blame] | 222 | def __rcmp__(b, a): |
| 223 | return cmp(Rat(a), b) |
Guido van Rossum | 0609f19 | 1997-05-13 19:25:57 +0000 | [diff] [blame] | 224 | |
Andrew M. Kuchling | 946c53e | 2003-04-24 17:13:18 +0000 | [diff] [blame] | 225 | # a != 0 |
| 226 | def __nonzero__(a): |
| 227 | return a.__num != 0 |
Guido van Rossum | 0609f19 | 1997-05-13 19:25:57 +0000 | [diff] [blame] | 228 | |
Andrew M. Kuchling | 946c53e | 2003-04-24 17:13:18 +0000 | [diff] [blame] | 229 | # coercion |
| 230 | def __coerce__(a, b): |
| 231 | return a, Rat(b) |
Guido van Rossum | e876949 | 1992-08-13 12:14:11 +0000 | [diff] [blame] | 232 | |
| 233 | def test(): |
Andrew M. Kuchling | 946c53e | 2003-04-24 17:13:18 +0000 | [diff] [blame] | 234 | '''\ |
| 235 | Test function for rat module. |
Guido van Rossum | 0609f19 | 1997-05-13 19:25:57 +0000 | [diff] [blame] | 236 | |
Andrew M. Kuchling | 946c53e | 2003-04-24 17:13:18 +0000 | [diff] [blame] | 237 | The expected output is (module some differences in floating |
| 238 | precission): |
| 239 | -1 |
| 240 | -1 |
| 241 | 0 0L 0.1 (0.1+0j) |
| 242 | [Rat(1,2), Rat(-3,10), Rat(1,25), Rat(1,4)] |
| 243 | [Rat(-3,10), Rat(1,25), Rat(1,4), Rat(1,2)] |
| 244 | 0 |
| 245 | (11/10) |
| 246 | (11/10) |
| 247 | 1.1 |
| 248 | OK |
| 249 | 2 1.5 (3/2) (1.5+1.5j) (15707963/5000000) |
| 250 | 2 2 2.0 (2+0j) |
Guido van Rossum | 0609f19 | 1997-05-13 19:25:57 +0000 | [diff] [blame] | 251 | |
Andrew M. Kuchling | 946c53e | 2003-04-24 17:13:18 +0000 | [diff] [blame] | 252 | 4 0 4 1 4 0 |
| 253 | 3.5 0.5 3.0 1.33333333333 2.82842712475 1 |
| 254 | (7/2) (1/2) 3 (4/3) 2.82842712475 1 |
| 255 | (3.5+1.5j) (0.5-1.5j) (3+3j) (0.666666666667-0.666666666667j) (1.43248815986+2.43884761145j) 1 |
| 256 | 1.5 1 1.5 (1.5+0j) |
Guido van Rossum | 0609f19 | 1997-05-13 19:25:57 +0000 | [diff] [blame] | 257 | |
Andrew M. Kuchling | 946c53e | 2003-04-24 17:13:18 +0000 | [diff] [blame] | 258 | 3.5 -0.5 3.0 0.75 2.25 -1 |
| 259 | 3.0 0.0 2.25 1.0 1.83711730709 0 |
| 260 | 3.0 0.0 2.25 1.0 1.83711730709 1 |
| 261 | (3+1.5j) -1.5j (2.25+2.25j) (0.5-0.5j) (1.50768393746+1.04970907623j) -1 |
| 262 | (3/2) 1 1.5 (1.5+0j) |
Guido van Rossum | 0609f19 | 1997-05-13 19:25:57 +0000 | [diff] [blame] | 263 | |
Andrew M. Kuchling | 946c53e | 2003-04-24 17:13:18 +0000 | [diff] [blame] | 264 | (7/2) (-1/2) 3 (3/4) (9/4) -1 |
| 265 | 3.0 0.0 2.25 1.0 1.83711730709 -1 |
| 266 | 3 0 (9/4) 1 1.83711730709 0 |
| 267 | (3+1.5j) -1.5j (2.25+2.25j) (0.5-0.5j) (1.50768393746+1.04970907623j) -1 |
| 268 | (1.5+1.5j) (1.5+1.5j) |
Guido van Rossum | 0609f19 | 1997-05-13 19:25:57 +0000 | [diff] [blame] | 269 | |
Andrew M. Kuchling | 946c53e | 2003-04-24 17:13:18 +0000 | [diff] [blame] | 270 | (3.5+1.5j) (-0.5+1.5j) (3+3j) (0.75+0.75j) 4.5j -1 |
| 271 | (3+1.5j) 1.5j (2.25+2.25j) (1+1j) (1.18235814075+2.85446505899j) 1 |
| 272 | (3+1.5j) 1.5j (2.25+2.25j) (1+1j) (1.18235814075+2.85446505899j) 1 |
| 273 | (3+3j) 0j 4.5j (1+0j) (-0.638110484918+0.705394566962j) 0 |
| 274 | ''' |
| 275 | print rat(-1L, 1) |
| 276 | print rat(1, -1) |
| 277 | a = rat(1, 10) |
| 278 | print int(a), long(a), float(a), complex(a) |
| 279 | b = rat(2, 5) |
| 280 | l = [a+b, a-b, a*b, a/b] |
| 281 | print l |
| 282 | l.sort() |
| 283 | print l |
| 284 | print rat(0, 1) |
| 285 | print a+1 |
| 286 | print a+1L |
| 287 | print a+1.0 |
| 288 | try: |
| 289 | print rat(1, 0) |
| 290 | raise SystemError, 'should have been ZeroDivisionError' |
| 291 | except ZeroDivisionError: |
| 292 | print 'OK' |
| 293 | print rat(2), rat(1.5), rat(3, 2), rat(1.5+1.5j), rat(31415926,10000000) |
| 294 | list = [2, 1.5, rat(3,2), 1.5+1.5j] |
| 295 | for i in list: |
| 296 | print i, |
| 297 | if not isinstance(i, complex): |
| 298 | print int(i), float(i), |
| 299 | print complex(i) |
| 300 | print |
| 301 | for j in list: |
| 302 | print i + j, i - j, i * j, i / j, i ** j, |
| 303 | if not (isinstance(i, complex) or |
| 304 | isinstance(j, complex)): |
| 305 | print cmp(i, j) |
| 306 | print |
Andrew M. Kuchling | 64b3c83 | 2003-04-24 16:59:45 +0000 | [diff] [blame] | 307 | |
Guido van Rossum | e876949 | 1992-08-13 12:14:11 +0000 | [diff] [blame] | 308 | |
Guido van Rossum | 0609f19 | 1997-05-13 19:25:57 +0000 | [diff] [blame] | 309 | if __name__ == '__main__': |
| 310 | test() |