PyXR

c:\python24\lib \ test \ test_binop.py



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
SourceForge.net Logo