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