0001 """Tests for binary operators on subtypes of built-in types.""" 0002 0003 import unittest 0004 from test import test_support 0005 0006 def gcd(a, b): 0007 """Greatest common divisor using Euclid's algorithm.""" 0008 while a: 0009 a, b = b%a, a 0010 return b 0011 0012 def isint(x): 0013 """Test whether an object is an instance of int or long.""" 0014 return isinstance(x, int) or isinstance(x, long) 0015 0016 def isnum(x): 0017 """Test whether an object is an instance of a built-in numeric type.""" 0018 for T in int, long, float, complex: 0019 if isinstance(x, T): 0020 return 1 0021 return 0 0022 0023 def isRat(x): 0024 """Test wheter an object is an instance of the Rat class.""" 0025 return isinstance(x, Rat) 0026 0027 class Rat(object): 0028 0029 """Rational number implemented as a normalized pair of longs.""" 0030 0031 __slots__ = ['_Rat__num', '_Rat__den'] 0032 0033 def __init__(self, num=0L, den=1L): 0034 """Constructor: Rat([num[, den]]). 0035 0036 The arguments must be ints or longs, and default to (0, 1).""" 0037 if not isint(num): 0038 raise TypeError, "Rat numerator must be int or long (%r)" % num 0039 if not isint(den): 0040 raise TypeError, "Rat denominator must be int or long (%r)" % den 0041 # But the zero is always on 0042 if den == 0: 0043 raise ZeroDivisionError, "zero denominator" 0044 g = gcd(den, num) 0045 self.__num = long(num//g) 0046 self.__den = long(den//g) 0047 0048 def _get_num(self): 0049 """Accessor function for read-only 'num' attribute of Rat.""" 0050 return self.__num 0051 num = property(_get_num, None) 0052 0053 def _get_den(self): 0054 """Accessor function for read-only 'den' attribute of Rat.""" 0055 return self.__den 0056 den = property(_get_den, None) 0057 0058 def __repr__(self): 0059 """Convert a Rat to an string resembling a Rat constructor call.""" 0060 return "Rat(%d, %d)" % (self.__num, self.__den) 0061 0062 def __str__(self): 0063 """Convert a Rat to a string resembling a decimal numeric value.""" 0064 return str(float(self)) 0065 0066 def __float__(self): 0067 """Convert a Rat to a float.""" 0068 return self.__num*1.0/self.__den 0069 0070 def __int__(self): 0071 """Convert a Rat to an int; self.den must be 1.""" 0072 if self.__den == 1: 0073 try: 0074 return int(self.__num) 0075 except OverflowError: 0076 raise OverflowError, ("%s too large to convert to int" % 0077 repr(self)) 0078 raise ValueError, "can't convert %s to int" % repr(self) 0079 0080 def __long__(self): 0081 """Convert a Rat to an long; self.den must be 1.""" 0082 if self.__den == 1: 0083 return long(self.__num) 0084 raise ValueError, "can't convert %s to long" % repr(self) 0085 0086 def __add__(self, other): 0087 """Add two Rats, or a Rat and a number.""" 0088 if isint(other): 0089 other = Rat(other) 0090 if isRat(other): 0091 return Rat(self.__num*other.__den + other.__num*self.__den, 0092 self.__den*other.__den) 0093 if isnum(other): 0094 return float(self) + other 0095 return NotImplemented 0096 0097 __radd__ = __add__ 0098 0099 def __sub__(self, other): 0100 """Subtract two Rats, or a Rat and a number.""" 0101 if isint(other): 0102 other = Rat(other) 0103 if isRat(other): 0104 return Rat(self.__num*other.__den - other.__num*self.__den, 0105 self.__den*other.__den) 0106 if isnum(other): 0107 return float(self) - other 0108 return NotImplemented 0109 0110 def __rsub__(self, other): 0111 """Subtract two Rats, or a Rat and a number (reversed args).""" 0112 if isint(other): 0113 other = Rat(other) 0114 if isRat(other): 0115 return Rat(other.__num*self.__den - self.__num*other.__den, 0116 self.__den*other.__den) 0117 if isnum(other): 0118 return other - float(self) 0119 return NotImplemented 0120 0121 def __mul__(self, other): 0122 """Multiply two Rats, or a Rat and a number.""" 0123 if isRat(other): 0124 return Rat(self.__num*other.__num, self.__den*other.__den) 0125 if isint(other): 0126 return Rat(self.__num*other, self.__den) 0127 if isnum(other): 0128 return float(self)*other 0129 return NotImplemented 0130 0131 __rmul__ = __mul__ 0132 0133 def __truediv__(self, other): 0134 """Divide two Rats, or a Rat and a number.""" 0135 if isRat(other): 0136 return Rat(self.__num*other.__den, self.__den*other.__num) 0137 if isint(other): 0138 return Rat(self.__num, self.__den*other) 0139 if isnum(other): 0140 return float(self) / other 0141 return NotImplemented 0142 0143 __div__ = __truediv__ 0144 0145 def __rtruediv__(self, other): 0146 """Divide two Rats, or a Rat and a number (reversed args).""" 0147 if isRat(other): 0148 return Rat(other.__num*self.__den, other.__den*self.__num) 0149 if isint(other): 0150 return Rat(other*self.__den, self.__num) 0151 if isnum(other): 0152 return other / float(self) 0153 return NotImplemented 0154 0155 __rdiv__ = __rtruediv__ 0156 0157 def __floordiv__(self, other): 0158 """Divide two Rats, returning the floored result.""" 0159 if isint(other): 0160 other = Rat(other) 0161 elif not isRat(other): 0162 return NotImplemented 0163 x = self/other 0164 return x.__num // x.__den 0165 0166 def __rfloordiv__(self, other): 0167 """Divide two Rats, returning the floored result (reversed args).""" 0168 x = other/self 0169 return x.__num // x.__den 0170 0171 def __divmod__(self, other): 0172 """Divide two Rats, returning quotient and remainder.""" 0173 if isint(other): 0174 other = Rat(other) 0175 elif not isRat(other): 0176 return NotImplemented 0177 x = self//other 0178 return (x, self - other * x) 0179 0180 def __rdivmod__(self, other): 0181 "Divide two Rats, returning quotient and remainder (reversed args).""" 0182 if isint(other): 0183 other = Rat(other) 0184 elif not isRat(other): 0185 return NotImplemented 0186 return divmod(other, self) 0187 0188 def __mod__(self, other): 0189 """Take one Rat modulo another.""" 0190 return divmod(self, other)[1] 0191 0192 def __rmod__(self, other): 0193 """Take one Rat modulo another (reversed args).""" 0194 return divmod(other, self)[1] 0195 0196 def __eq__(self, other): 0197 """Compare two Rats for equality.""" 0198 if isint(other): 0199 return self.__den == 1 and self.__num == other 0200 if isRat(other): 0201 return self.__num == other.__num and self.__den == other.__den 0202 if isnum(other): 0203 return float(self) == other 0204 return NotImplemented 0205 0206 def __ne__(self, other): 0207 """Compare two Rats for inequality.""" 0208 return not self == other 0209 0210 class RatTestCase(unittest.TestCase): 0211 """Unit tests for Rat class and its support utilities.""" 0212 0213 def test_gcd(self): 0214 self.assertEqual(gcd(10, 12), 2) 0215 self.assertEqual(gcd(10, 15), 5) 0216 self.assertEqual(gcd(10, 11), 1) 0217 self.assertEqual(gcd(100, 15), 5) 0218 self.assertEqual(gcd(-10, 2), -2) 0219 self.assertEqual(gcd(10, -2), 2) 0220 self.assertEqual(gcd(-10, -2), -2) 0221 for i in range(1, 20): 0222 for j in range(1, 20): 0223 self.assert_(gcd(i, j) > 0) 0224 self.assert_(gcd(-i, j) < 0) 0225 self.assert_(gcd(i, -j) > 0) 0226 self.assert_(gcd(-i, -j) < 0) 0227 0228 def test_constructor(self): 0229 a = Rat(10, 15) 0230 self.assertEqual(a.num, 2) 0231 self.assertEqual(a.den, 3) 0232 a = Rat(10L, 15L) 0233 self.assertEqual(a.num, 2) 0234 self.assertEqual(a.den, 3) 0235 a = Rat(10, -15) 0236 self.assertEqual(a.num, -2) 0237 self.assertEqual(a.den, 3) 0238 a = Rat(-10, 15) 0239 self.assertEqual(a.num, -2) 0240 self.assertEqual(a.den, 3) 0241 a = Rat(-10, -15) 0242 self.assertEqual(a.num, 2) 0243 self.assertEqual(a.den, 3) 0244 a = Rat(7) 0245 self.assertEqual(a.num, 7) 0246 self.assertEqual(a.den, 1) 0247 try: 0248 a = Rat(1, 0) 0249 except ZeroDivisionError: 0250 pass 0251 else: 0252 self.fail("Rat(1, 0) didn't raise ZeroDivisionError") 0253 for bad in "0", 0.0, 0j, (), [], {}, None, Rat, unittest: 0254 try: 0255 a = Rat(bad) 0256 except TypeError: 0257 pass 0258 else: 0259 self.fail("Rat(%r) didn't raise TypeError" % bad) 0260 try: 0261 a = Rat(1, bad) 0262 except TypeError: 0263 pass 0264 else: 0265 self.fail("Rat(1, %r) didn't raise TypeError" % bad) 0266 0267 def test_add(self): 0268 self.assertEqual(Rat(2, 3) + Rat(1, 3), 1) 0269 self.assertEqual(Rat(2, 3) + 1, Rat(5, 3)) 0270 self.assertEqual(1 + Rat(2, 3), Rat(5, 3)) 0271 self.assertEqual(1.0 + Rat(1, 2), 1.5) 0272 self.assertEqual(Rat(1, 2) + 1.0, 1.5) 0273 0274 def test_sub(self): 0275 self.assertEqual(Rat(7, 2) - Rat(7, 5), Rat(21, 10)) 0276 self.assertEqual(Rat(7, 5) - 1, Rat(2, 5)) 0277 self.assertEqual(1 - Rat(3, 5), Rat(2, 5)) 0278 self.assertEqual(Rat(3, 2) - 1.0, 0.5) 0279 self.assertEqual(1.0 - Rat(1, 2), 0.5) 0280 0281 def test_mul(self): 0282 self.assertEqual(Rat(2, 3) * Rat(5, 7), Rat(10, 21)) 0283 self.assertEqual(Rat(10, 3) * 3, 10) 0284 self.assertEqual(3 * Rat(10, 3), 10) 0285 self.assertEqual(Rat(10, 5) * 0.5, 1.0) 0286 self.assertEqual(0.5 * Rat(10, 5), 1.0) 0287 0288 def test_div(self): 0289 self.assertEqual(Rat(10, 3) / Rat(5, 7), Rat(14, 3)) 0290 self.assertEqual(Rat(10, 3) / 3, Rat(10, 9)) 0291 self.assertEqual(2 / Rat(5), Rat(2, 5)) 0292 self.assertEqual(3.0 * Rat(1, 2), 1.5) 0293 self.assertEqual(Rat(1, 2) * 3.0, 1.5) 0294 0295 def test_floordiv(self): 0296 self.assertEqual(Rat(10) // Rat(4), 2) 0297 self.assertEqual(Rat(10, 3) // Rat(4, 3), 2) 0298 self.assertEqual(Rat(10) // 4, 2) 0299 self.assertEqual(10 // Rat(4), 2) 0300 0301 def test_eq(self): 0302 self.assertEqual(Rat(10), Rat(20, 2)) 0303 self.assertEqual(Rat(10), 10) 0304 self.assertEqual(10, Rat(10)) 0305 self.assertEqual(Rat(10), 10.0) 0306 self.assertEqual(10.0, Rat(10)) 0307 0308 def test_future_div(self): 0309 exec future_test 0310 0311 # XXX Ran out of steam; TO DO: divmod, div, future division 0312 0313 future_test = """ 0314 from __future__ import division 0315 self.assertEqual(Rat(10, 3) / Rat(5, 7), Rat(14, 3)) 0316 self.assertEqual(Rat(10, 3) / 3, Rat(10, 9)) 0317 self.assertEqual(2 / Rat(5), Rat(2, 5)) 0318 self.assertEqual(3.0 * Rat(1, 2), 1.5) 0319 self.assertEqual(Rat(1, 2) * 3.0, 1.5) 0320 self.assertEqual(eval('1/2'), 0.5) 0321 """ 0322 0323 def test_main(): 0324 test_support.run_unittest(RatTestCase) 0325 0326 0327 if __name__ == "__main__": 0328 test_main() 0329
Generated by PyXR 0.9.4