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 # Silence Py3k warning
213 class RatTestCase(unittest
.TestCase
):
214 """Unit tests for Rat class and its support utilities."""
217 self
.assertEqual(gcd(10, 12), 2)
218 self
.assertEqual(gcd(10, 15), 5)
219 self
.assertEqual(gcd(10, 11), 1)
220 self
.assertEqual(gcd(100, 15), 5)
221 self
.assertEqual(gcd(-10, 2), -2)
222 self
.assertEqual(gcd(10, -2), 2)
223 self
.assertEqual(gcd(-10, -2), -2)
224 for i
in range(1, 20):
225 for j
in range(1, 20):
226 self
.assertTrue(gcd(i
, j
) > 0)
227 self
.assertTrue(gcd(-i
, j
) < 0)
228 self
.assertTrue(gcd(i
, -j
) > 0)
229 self
.assertTrue(gcd(-i
, -j
) < 0)
231 def test_constructor(self
):
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
, 2)
246 self
.assertEqual(a
.den
, 3)
248 self
.assertEqual(a
.num
, 7)
249 self
.assertEqual(a
.den
, 1)
252 except ZeroDivisionError:
255 self
.fail("Rat(1, 0) didn't raise ZeroDivisionError")
256 for bad
in "0", 0.0, 0j
, (), [], {}, None, Rat
, unittest
:
262 self
.fail("Rat(%r) didn't raise TypeError" % bad
)
268 self
.fail("Rat(1, %r) didn't raise TypeError" % bad
)
271 self
.assertEqual(Rat(2, 3) + Rat(1, 3), 1)
272 self
.assertEqual(Rat(2, 3) + 1, Rat(5, 3))
273 self
.assertEqual(1 + Rat(2, 3), Rat(5, 3))
274 self
.assertEqual(1.0 + Rat(1, 2), 1.5)
275 self
.assertEqual(Rat(1, 2) + 1.0, 1.5)
278 self
.assertEqual(Rat(7, 2) - Rat(7, 5), Rat(21, 10))
279 self
.assertEqual(Rat(7, 5) - 1, Rat(2, 5))
280 self
.assertEqual(1 - Rat(3, 5), Rat(2, 5))
281 self
.assertEqual(Rat(3, 2) - 1.0, 0.5)
282 self
.assertEqual(1.0 - Rat(1, 2), 0.5)
285 self
.assertEqual(Rat(2, 3) * Rat(5, 7), Rat(10, 21))
286 self
.assertEqual(Rat(10, 3) * 3, 10)
287 self
.assertEqual(3 * Rat(10, 3), 10)
288 self
.assertEqual(Rat(10, 5) * 0.5, 1.0)
289 self
.assertEqual(0.5 * Rat(10, 5), 1.0)
292 self
.assertEqual(Rat(10, 3) / Rat(5, 7), Rat(14, 3))
293 self
.assertEqual(Rat(10, 3) / 3, Rat(10, 9))
294 self
.assertEqual(2 / Rat(5), Rat(2, 5))
295 self
.assertEqual(3.0 * Rat(1, 2), 1.5)
296 self
.assertEqual(Rat(1, 2) * 3.0, 1.5)
298 def test_floordiv(self
):
299 self
.assertEqual(Rat(10) // Rat(4), 2)
300 self
.assertEqual(Rat(10, 3) // Rat(4, 3), 2)
301 self
.assertEqual(Rat(10) // 4, 2)
302 self
.assertEqual(10 // Rat(4), 2)
305 self
.assertEqual(Rat(10), Rat(20, 2))
306 self
.assertEqual(Rat(10), 10)
307 self
.assertEqual(10, Rat(10))
308 self
.assertEqual(Rat(10), 10.0)
309 self
.assertEqual(10.0, Rat(10))
311 def test_future_div(self
):
314 # XXX Ran out of steam; TO DO: divmod, div, future division
317 from __future__ import division
318 self.assertEqual(Rat(10, 3) / Rat(5, 7), Rat(14, 3))
319 self.assertEqual(Rat(10, 3) / 3, Rat(10, 9))
320 self.assertEqual(2 / Rat(5), Rat(2, 5))
321 self.assertEqual(3.0 * Rat(1, 2), 1.5)
322 self.assertEqual(Rat(1, 2) * 3.0, 1.5)
323 self.assertEqual(eval('1/2'), 0.5)
327 test_support
.run_unittest(RatTestCase
)
330 if __name__
== "__main__":