source: trunk/essentials/dev-lang/python/Demo/classes/Rat.py

Last change on this file was 3225, checked in by bird, 18 years ago

Python 2.5

File size: 8.6 KB
Line 
1'''\
2This module implements rational numbers.
3
4The entry point of this module is the function
5 rat(numerator, denominator)
6If either numerator or denominator is of an integral or rational type,
7the result is a rational number, else, the result is the simplest of
8the types float and complex which can hold numerator/denominator.
9If denominator is omitted, it defaults to 1.
10Rational numbers can be used in calculations with any other numeric
11type. The result of the calculation will be rational if possible.
12
13There is also a test function with calling sequence
14 test()
15The documentation string of the test function contains the expected
16output.
17'''
18
19# Contributed by Sjoerd Mullender
20
21from types import *
22
23def gcd(a, b):
24 '''Calculate the Greatest Common Divisor.'''
25 while b:
26 a, b = b, a%b
27 return a
28
29def 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
40class 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
233def 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
309if __name__ == '__main__':
310 test()
Note: See TracBrowser for help on using the repository browser.