issue1172: Documentation of "done" attribute in cgi module.
[python.git] / Demo / classes / Rat.py
blob55543b6d2d249391b6da9e6c0c9e0c4e887c1ef1
1 '''\
2 This module implements rational numbers.
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.
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 '''
19 # Contributed by Sjoerd Mullender
21 from types import *
23 def gcd(a, b):
24 '''Calculate the Greatest Common Divisor.'''
25 while b:
26 a, b = b, a%b
27 return a
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)
40 class Rat:
41 '''This class implements rational numbers.'''
43 def __init__(self, num, den = 1):
44 if den == 0:
45 raise ZeroDivisionError, 'rat(x, 0)'
47 # normalize
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
94 def __repr__(self):
95 return 'Rat(%s,%s)' % (self.__num, self.__den)
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))
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))
113 def __radd__(b, a):
114 return Rat(a) + b
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))
126 def __rsub__(b, a):
127 return Rat(a) - b
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))
137 def __rmul__(b, a):
138 return Rat(a) * b
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))
148 def __rdiv__(b, a):
149 return Rat(a) / b
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
160 def __rmod__(b, a):
161 return Rat(a) % b
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)
181 def __rpow__(b, a):
182 return Rat(a) ** b
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)
192 # abs(a)
193 def __abs__(a):
194 return rat(abs(a.__num), a.__den)
196 # int(a)
197 def __int__(a):
198 return int(a.__num / a.__den)
200 # long(a)
201 def __long__(a):
202 return long(a.__num) / long(a.__den)
204 # float(a)
205 def __float__(a):
206 return float(a.__num) / float(a.__den)
208 # complex(a)
209 def __complex__(a):
210 return complex(a.__num) / complex(a.__den)
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
222 def __rcmp__(b, a):
223 return cmp(Rat(a), b)
225 # a != 0
226 def __nonzero__(a):
227 return a.__num != 0
229 # coercion
230 def __coerce__(a, b):
231 return a, Rat(b)
233 def test():
234 '''\
235 Test function for rat module.
237 The expected output is (module some differences in floating
238 precission):
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)]
245 (11/10)
246 (11/10)
249 2 1.5 (3/2) (1.5+1.5j) (15707963/5000000)
250 2 2 2.0 (2+0j)
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)
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)
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)
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
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
309 if __name__ == '__main__':
310 test()