1 """Tests for binary operators on subtypes of built-in types."""
4 from test
import test_support
7 """Greatest common divisor using Euclid's algorithm."""
13 """Test whether an object is an instance of int or long."""
14 return isinstance(x
, int) or isinstance(x
, long)
17 """Test whether an object is an instance of a built-in numeric type."""
18 for T
in int, long, float, complex:
24 """Test wheter an object is an instance of the Rat class."""
25 return isinstance(x
, Rat
)
29 """Rational number implemented as a normalized pair of longs."""
31 __slots__
= ['_Rat__num', '_Rat__den']
33 def __init__(self
, num
=0L, den
=1L):
34 """Constructor: Rat([num[, den]]).
36 The arguments must be ints or longs, and default to (0, 1)."""
38 raise TypeError, "Rat numerator must be int or long (%r)" % num
40 raise TypeError, "Rat denominator must be int or long (%r)" % den
41 # But the zero is always on
43 raise ZeroDivisionError, "zero denominator"
45 self
.__num
= long(num
//g
)
46 self
.__den
= long(den
//g
)
49 """Accessor function for read-only 'num' attribute of Rat."""
51 num
= property(_get_num
, None)
54 """Accessor function for read-only 'den' attribute of Rat."""
56 den
= property(_get_den
, None)
59 """Convert a Rat to an string resembling a Rat constructor call."""
60 return "Rat(%d, %d)" % (self
.__num
, self
.__den
)
63 """Convert a Rat to a string resembling a decimal numeric value."""
64 return str(float(self
))
67 """Convert a Rat to a float."""
68 return self
.__num
*1.0/self
.__den
71 """Convert a Rat to an int; self.den must be 1."""
74 return int(self
.__num
)
76 raise OverflowError, ("%s too large to convert to int" %
78 raise ValueError, "can't convert %s to int" % repr(self
)
81 """Convert a Rat to an long; self.den must be 1."""
83 return long(self
.__num
)
84 raise ValueError, "can't convert %s to long" % repr(self
)
86 def __add__(self
, other
):
87 """Add two Rats, or a Rat and a number."""
91 return Rat(self
.__num
*other
.__den
+ other
.__num
*self
.__den
,
92 self
.__den
*other
.__den
)
94 return float(self
) + other
99 def __sub__(self
, other
):
100 """Subtract two Rats, or a Rat and a number."""
104 return Rat(self
.__num
*other
.__den
- other
.__num
*self
.__den
,
105 self
.__den
*other
.__den
)
107 return float(self
) - other
108 return NotImplemented
110 def __rsub__(self
, other
):
111 """Subtract two Rats, or a Rat and a number (reversed args)."""
115 return Rat(other
.__num
*self
.__den
- self
.__num
*other
.__den
,
116 self
.__den
*other
.__den
)
118 return other
- float(self
)
119 return NotImplemented
121 def __mul__(self
, other
):
122 """Multiply two Rats, or a Rat and a number."""
124 return Rat(self
.__num
*other
.__num
, self
.__den
*other
.__den
)
126 return Rat(self
.__num
*other
, self
.__den
)
128 return float(self
)*other
129 return NotImplemented
133 def __truediv__(self
, other
):
134 """Divide two Rats, or a Rat and a number."""
136 return Rat(self
.__num
*other
.__den
, self
.__den
*other
.__num
)
138 return Rat(self
.__num
, self
.__den
*other
)
140 return float(self
) / other
141 return NotImplemented
143 __div__
= __truediv__
145 def __rtruediv__(self
, other
):
146 """Divide two Rats, or a Rat and a number (reversed args)."""
148 return Rat(other
.__num
*self
.__den
, other
.__den
*self
.__num
)
150 return Rat(other
*self
.__den
, self
.__num
)
152 return other
/ float(self
)
153 return NotImplemented
155 __rdiv__
= __rtruediv__
157 def __floordiv__(self
, other
):
158 """Divide two Rats, returning the floored result."""
161 elif not isRat(other
):
162 return NotImplemented
164 return x
.__num
// x
.__den
166 def __rfloordiv__(self
, other
):
167 """Divide two Rats, returning the floored result (reversed args)."""
169 return x
.__num
// x
.__den
171 def __divmod__(self
, other
):
172 """Divide two Rats, returning quotient and remainder."""
175 elif not isRat(other
):
176 return NotImplemented
178 return (x
, self
- other
* x
)
180 def __rdivmod__(self
, other
):
181 "Divide two Rats, returning quotient and remainder (reversed args)."""
184 elif not isRat(other):
185 return NotImplemented
186 return divmod(other, self)
188 def __mod__(self, other):
189 """Take one Rat modulo another."""
190 return divmod(self, other)[1]
192 def __rmod__(self, other):
193 """Take one Rat modulo another (reversed args)."""
194 return divmod(other, self)[1]
196 def __eq__(self, other):
197 """Compare two Rats for equality."""
199 return self.__den == 1 and self.__num == other
201 return self.__num == other.__num and self.__den == other.__den
203 return float(self) == other
204 return NotImplemented
206 def __ne__(self, other):
207 """Compare two Rats for inequality."""
208 return not self == other
210 class RatTestCase(unittest.TestCase):
211 """Unit tests for Rat class and its support utilities."""
214 self.assertEqual(gcd(10, 12), 2)
215 self.assertEqual(gcd(10, 15), 5)
216 self.assertEqual(gcd(10, 11), 1)
217 self.assertEqual(gcd(100, 15), 5)
218 self.assertEqual(gcd(-10, 2), -2)
219 self.assertEqual(gcd(10, -2), 2)
220 self.assertEqual(gcd(-10, -2), -2)
221 for i in range(1, 20):
222 for j in range(1, 20):
223 self.assert_(gcd(i, j) > 0)
224 self.assert_(gcd(-i, j) < 0)
225 self.assert_(gcd(i, -j) > 0)
226 self.assert_(gcd(-i, -j) < 0)
228 def test_constructor(self):
230 self.assertEqual(a.num, 2)
231 self.assertEqual(a.den, 3)
233 self.assertEqual(a.num, 2)
234 self.assertEqual(a.den, 3)
236 self.assertEqual(a.num, -2)
237 self.assertEqual(a.den, 3)
239 self.assertEqual(a.num, -2)
240 self.assertEqual(a.den, 3)
242 self.assertEqual(a.num, 2)
243 self.assertEqual(a.den, 3)
245 self.assertEqual(a.num, 7)
246 self.assertEqual(a.den, 1)
249 except ZeroDivisionError:
252 self.fail("Rat(1, 0) didn
't raise ZeroDivisionError")
253 for bad in "0", 0.0, 0j, (), [], {}, None, Rat, unittest:
259 self.fail("Rat(%r) didn't
raise TypeError" % bad)
265 self.fail("Rat(1, %r) didn
't raise TypeError" % bad)
268 self.assertEqual(Rat(2, 3) + Rat(1, 3), 1)
269 self.assertEqual(Rat(2, 3) + 1, Rat(5, 3))
270 self.assertEqual(1 + Rat(2, 3), Rat(5, 3))
271 self.assertEqual(1.0 + Rat(1, 2), 1.5)
272 self.assertEqual(Rat(1, 2) + 1.0, 1.5)
275 self.assertEqual(Rat(7, 2) - Rat(7, 5), Rat(21, 10))
276 self.assertEqual(Rat(7, 5) - 1, Rat(2, 5))
277 self.assertEqual(1 - Rat(3, 5), Rat(2, 5))
278 self.assertEqual(Rat(3, 2) - 1.0, 0.5)
279 self.assertEqual(1.0 - Rat(1, 2), 0.5)
282 self.assertEqual(Rat(2, 3) * Rat(5, 7), Rat(10, 21))
283 self.assertEqual(Rat(10, 3) * 3, 10)
284 self.assertEqual(3 * Rat(10, 3), 10)
285 self.assertEqual(Rat(10, 5) * 0.5, 1.0)
286 self.assertEqual(0.5 * Rat(10, 5), 1.0)
289 self.assertEqual(Rat(10, 3) / Rat(5, 7), Rat(14, 3))
290 self.assertEqual(Rat(10, 3) / 3, Rat(10, 9))
291 self.assertEqual(2 / Rat(5), Rat(2, 5))
292 self.assertEqual(3.0 * Rat(1, 2), 1.5)
293 self.assertEqual(Rat(1, 2) * 3.0, 1.5)
295 def test_floordiv(self):
296 self.assertEqual(Rat(10) // Rat(4), 2)
297 self.assertEqual(Rat(10, 3) // Rat(4, 3), 2)
298 self.assertEqual(Rat(10) // 4, 2)
299 self.assertEqual(10 // Rat(4), 2)
302 self.assertEqual(Rat(10), Rat(20, 2))
303 self.assertEqual(Rat(10), 10)
304 self.assertEqual(10, Rat(10))
305 self.assertEqual(Rat(10), 10.0)
306 self.assertEqual(10.0, Rat(10))
308 def test_future_div(self):
311 # XXX Ran out of steam; TO DO: divmod, div, future division
314 from __future__ import division
315 self.assertEqual(Rat(10, 3) / Rat(5, 7), Rat(14, 3))
316 self.assertEqual(Rat(10, 3) / 3, Rat(10, 9))
317 self.assertEqual(2 / Rat(5), Rat(2, 5))
318 self.assertEqual(3.0 * Rat(1, 2), 1.5)
319 self.assertEqual(Rat(1, 2) * 3.0, 1.5)
320 self.assertEqual(eval('1/2'), 0.5)
324 test_support.run_unittest(RatTestCase)
327 if __name__ == "__main__":