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
|
---|
20 |
|
---|
21 | from types import *
|
---|
22 |
|
---|
23 | def gcd(a, b):
|
---|
24 | '''Calculate the Greatest Common Divisor.'''
|
---|
25 | while b:
|
---|
26 | a, b = b, a%b
|
---|
27 | return a
|
---|
28 |
|
---|
29 | def rat(num, den = 1):
|
---|
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)
|
---|
39 |
|
---|
40 | class Rat:
|
---|
41 | '''This class implements rational numbers.'''
|
---|
42 |
|
---|
43 | def __init__(self, num, den = 1):
|
---|
44 | if den == 0:
|
---|
45 | raise ZeroDivisionError, 'rat(x, 0)'
|
---|
46 |
|
---|
47 | # normalize
|
---|
48 |
|
---|
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
|
---|
93 |
|
---|
94 | def __repr__(self):
|
---|
95 | return 'Rat(%s,%s)' % (self.__num, self.__den)
|
---|
96 |
|
---|
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))
|
---|
102 |
|
---|
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))
|
---|
112 |
|
---|
113 | def __radd__(b, a):
|
---|
114 | return Rat(a) + b
|
---|
115 |
|
---|
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))
|
---|
125 |
|
---|
126 | def __rsub__(b, a):
|
---|
127 | return Rat(a) - b
|
---|
128 |
|
---|
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))
|
---|
136 |
|
---|
137 | def __rmul__(b, a):
|
---|
138 | return Rat(a) * b
|
---|
139 |
|
---|
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))
|
---|
147 |
|
---|
148 | def __rdiv__(b, a):
|
---|
149 | return Rat(a) / b
|
---|
150 |
|
---|
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
|
---|
159 |
|
---|
160 | def __rmod__(b, a):
|
---|
161 | return Rat(a) % b
|
---|
162 |
|
---|
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)
|
---|
180 |
|
---|
181 | def __rpow__(b, a):
|
---|
182 | return Rat(a) ** b
|
---|
183 |
|
---|
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)
|
---|
191 |
|
---|
192 | # abs(a)
|
---|
193 | def __abs__(a):
|
---|
194 | return rat(abs(a.__num), a.__den)
|
---|
195 |
|
---|
196 | # int(a)
|
---|
197 | def __int__(a):
|
---|
198 | return int(a.__num / a.__den)
|
---|
199 |
|
---|
200 | # long(a)
|
---|
201 | def __long__(a):
|
---|
202 | return long(a.__num) / long(a.__den)
|
---|
203 |
|
---|
204 | # float(a)
|
---|
205 | def __float__(a):
|
---|
206 | return float(a.__num) / float(a.__den)
|
---|
207 |
|
---|
208 | # complex(a)
|
---|
209 | def __complex__(a):
|
---|
210 | return complex(a.__num) / complex(a.__den)
|
---|
211 |
|
---|
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
|
---|
221 |
|
---|
222 | def __rcmp__(b, a):
|
---|
223 | return cmp(Rat(a), b)
|
---|
224 |
|
---|
225 | # a != 0
|
---|
226 | def __nonzero__(a):
|
---|
227 | return a.__num != 0
|
---|
228 |
|
---|
229 | # coercion
|
---|
230 | def __coerce__(a, b):
|
---|
231 | return a, Rat(b)
|
---|
232 |
|
---|
233 | def test():
|
---|
234 | '''\
|
---|
235 | Test function for rat module.
|
---|
236 |
|
---|
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)
|
---|
251 |
|
---|
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)
|
---|
257 |
|
---|
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)
|
---|
263 |
|
---|
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)
|
---|
269 |
|
---|
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
|
---|
307 |
|
---|
308 |
|
---|
309 | if __name__ == '__main__':
|
---|
310 | test()
|
---|