]> granicus.if.org Git - python/commitdiff
A completely new Rat.py by Sjoerd.
authorGuido van Rossum <guido@python.org>
Tue, 13 May 1997 19:25:57 +0000 (19:25 +0000)
committerGuido van Rossum <guido@python.org>
Tue, 13 May 1997 19:25:57 +0000 (19:25 +0000)
Demo/classes/Rat.py

index 755374570611e21c6cde2bcc14612c74427a692e..5273e3230b9b59bd917eca9f64e9445d909f0249 100755 (executable)
-# Rational numbers
+'''\
+This module implements rational numbers.
 
-from types import *
+The entry point of this module is the function
+       rat(numerator, denominator)
+If either numerator or denominator is of an integral or rational type,
+the result is a rational number, else, the result is the simplest of
+the types float and complex which can hold numerator/denominator.
+If denominator is omitted, it defaults to 1.
+Rational numbers can be used in calculations with any other numeric
+type.  The result of the calculation will be rational if possible.
 
-def rat(num, den):
-       if type(num) == FloatType or type(den) == FloatType:
-               return num/den
-       return Rat(num, den)
+There is also a test function with calling sequence
+       test()
+The documentation string of the test function contains the expected
+output.
+'''
 
+# Contributed by Sjoerd Mullender
+
+from types import *
 
 def gcd(a, b):
+       '''Calculate the Greatest Common Divisor.'''
        while b:
                a, b = b, a%b
        return a
 
+def rat(num, den = 1):
+       # must check complex before float
+       if type(num) is ComplexType or type(den) is ComplexType:
+               # numerator or denominator is complex: return a complex
+               return complex(num) / complex(den)
+       if type(num) is FloatType or type(den) is FloatType:
+               # numerator or denominator is float: return a float
+               return float(num) / float(den)
+       # otherwise return a rational
+       return Rat(num, den)
 
 class Rat:
+       '''This class implements rational numbers.'''
 
-       def __init__(self, num, den):
+       def __init__(self, num, den = 1):
                if den == 0:
                        raise ZeroDivisionError, 'rat(x, 0)'
-               if type(den) == FloatType or type(num) == FloatType:
-                       g = float(den)
+
+               # normalize
+
+               # must check complex before float
+               if type(num) is ComplexType or type(den) is ComplexType:
+                       # numerator or denominator is complex:
+                       # normalized form has denominator == 1+0j
+                       self.__num = complex(num) / complex(den)
+                       self.__den = complex(1)
+                       return
+               if type(num) is FloatType or type(den) is FloatType:
+                       # numerator or denominator is float:
+                       # normalized form has denominator == 1.0
+                       self.__num = float(num) / float(den)
+                       self.__den = 1.0
+                       return
+               if (type(num) is InstanceType and
+                   num.__class__ is self.__class__) or \
+                  (type(den) is InstanceType and
+                   den.__class__ is self.__class__):
+                       # numerator or denominator is rational
+                       new = num / den
+                       if type(new) is not InstanceType or \
+                          new.__class__ is not self.__class__:
+                               self.__num = new
+                               if type(new) is ComplexType:
+                                       self.__den = complex(1)
+                               else:
+                                       self.__den = 1.0
+                       else:
+                               self.__num = new.__num
+                               self.__den = new.__den
                else:
+                       # make sure numerator and denominator don't
+                       # have common factors
+                       # this also makes sure that denominator > 0
                        g = gcd(num, den)
-               self.num = num/g
-               self.den = den/g
+                       self.__num = num / g
+                       self.__den = den / g
+               # try making numerator and denominator of IntType if they fit
+               try:
+                       numi = int(self.__num)
+                       deni = int(self.__den)
+               except (OverflowError, TypeError):
+                       pass
+               else:
+                       if self.__num == numi and self.__den == deni:
+                               self.__num = numi
+                               self.__den = deni
 
        def __repr__(self):
-               return 'Rat(%s, %s)' % (self.num, self.den)
+               return 'Rat(%s,%s)' % (self.__num, self.__den)
 
        def __str__(self):
-               if self.den == 1:
-                       return str(self.num)
+               if self.__den == 1:
+                       return str(self.__num)
                else:
-                       return '%s/%s' % (self.num, self.den)
+                       return '%s/%s' % (str(self.__num), str(self.__den))
+
+       # a + b
+       def __add__(a, b):
+               try:
+                       return rat(a.__num * b.__den + b.__num * a.__den,
+                                  a.__den * b.__den)
+               except OverflowError:
+                       return rat(long(a.__num) * long(b.__den) +
+                                  long(b.__num) * long(a.__den),
+                                  long(a.__den) * long(b.__den))
+
+       def __radd__(b, a):
+               return Rat(a) + b
+
+       # a - b
+       def __sub__(a, b):
+               try:
+                       return rat(a.__num * b.__den - b.__num * a.__den,
+                                  a.__den * b.__den)
+               except OverflowError:
+                       return rat(long(a.__num) * long(b.__den) -
+                                  long(b.__num) * long(a.__den),
+                                  long(a.__den) * long(b.__den))
+
+       def __rsub__(b, a):
+               return Rat(a) - b
+
+       # a * b
+       def __mul__(a, b):
+               try:
+                       return rat(a.__num * b.__num, a.__den * b.__den)
+               except OverflowError:
+                       return rat(long(a.__num) * long(b.__num),
+                                  long(a.__den) * long(b.__den))
+
+       def __rmul__(b, a):
+               return Rat(a) * b
+
+       # a / b
+       def __div__(a, b):
+               try:
+                       return rat(a.__num * b.__den, a.__den * b.__num)
+               except OverflowError:
+                       return rat(long(a.__num) * long(b.__den),
+                                  long(a.__den) * long(b.__num))
+
+       def __rdiv__(b, a):
+               return Rat(a) / b
 
+       # a % b
+       def __mod__(a, b):
+               div = a / b
+               try:
+                       div = int(div)
+               except OverflowError:
+                       div = long(div)
+               return a - b * div
+
+       def __rmod__(b, a):
+               return Rat(a) % b
+
+       # a ** b
+       def __pow__(a, b):
+               if b.__den != 1:
+                       if type(a.__num) is ComplexType:
+                               a = complex(a)
+                       else:
+                               a = float(a)
+                       if type(b.__num) is ComplexType:
+                               b = complex(b)
+                       else:
+                               b = float(b)
+                       return a ** b
+               try:
+                       return rat(a.__num ** b.__num, a.__den ** b.__num)
+               except OverflowError:
+                       return rat(long(a.__num) ** b.__num,
+                                  long(a.__den) ** b.__num)
+
+       def __rpow__(b, a):
+               return Rat(a) ** b
+
+       # -a
+       def __neg__(a):
+               try:
+                       return rat(-a.__num, a.__den)
+               except OverflowError:
+                       # a.__num == sys.maxint
+                       return rat(-long(a.__num), a.__den)
+
+       # abs(a)
+       def __abs__(a):
+               return rat(abs(a.__num), a.__den)
+
+       # int(a)
+       def __int__(a):
+               return int(a.__num / a.__den)
+
+       # long(a)
+       def __long__(a):
+               return long(a.__num) / long(a.__den)
+
+       # float(a)
+       def __float__(a):
+               return float(a.__num) / float(a.__den)
+
+       # complex(a)
+       def __complex__(a):
+               return complex(a.__num) / complex(a.__den)
+
+       # cmp(a,b)
        def __cmp__(a, b):
-               c = a-b
-               if c.num < 0:
+               diff = a - b
+               if diff.__num < 0:
                        return -1
-               if c.num > 0:
+               elif diff.__num > 0:
                        return 1
-               return 0
-
-       def __float__(self):
-               return float(self.num) / float(self.den)
+               else:
+                       return 0
 
-       def __long__(self):
-               return long(self.num) / long(self.den)
+       def __rcmp__(b, a):
+                  return cmp(Rat(a), b)
 
-       def __int__(self):
-               return int(self.num / self.den)
+       # a != 0
+       def __nonzero__(a):
+               return a.__num != 0
 
+       # coercion
        def __coerce__(a, b):
-               t = type(b)
-               if t == IntType:
-                       return a, Rat(b, 1)
-               if t == LongType:
-                       return a, Rat(b, 1L)
-               if t == FloatType:
-                       return a, Rat(b, 1.0)
-               if t == InstanceType and a.__class__ == b.__class__:
-                       return a, b
-               raise TypeError, 'Rat.__coerce__: bad other arg'
+               return a, Rat(b)
 
-       def __add__(a, b):
-               return rat(a.num*b.den + b.num*a.den, a.den*b.den)
-
-       def __sub__(a, b):
-               return rat(a.num*b.den - b.num*a.den, a.den*b.den)
+def test():
+       '''\
+       Test function for rat module.
 
-       def __mul__(a, b):
-               return rat(a.num*b.num, a.den*b.den)
+       The expected output is (module some differences in floating
+       precission):
+       -1
+       -1
+       0 0L 0.1 (0.1+0j)
+       [Rat(1,2), Rat(-3,10), Rat(1,25), Rat(1,4)]
+       [Rat(-3,10), Rat(1,25), Rat(1,4), Rat(1,2)]
+       0
+       11/10
+       11/10
+       1.1
+       OK
+       2 1.5 3/2 (1.5+1.5j) 15707963/5000000
+       2 2 2.0 (2+0j)
 
-       def __div__(a, b):
-               return rat(a.num*b.den, a.den*b.num)
+       4 0 4 1 4 0
+       3.5 0.5 3.0 1.33333333333 2.82842712475 1
+       7/2 1/2 3 4/3 2.82842712475 1
+       (3.5+1.5j) (0.5-1.5j) (3+3j) (0.666666666667-0.666666666667j) (1.43248815986+2.43884761145j) 1
+       1.5 1 1.5 (1.5+0j)
 
-       def __neg__(self):
-               return rat(-self.num, self.den)
+       3.5 -0.5 3.0 0.75 2.25 -1
+       3.0 0.0 2.25 1.0 1.83711730709 0
+       3.0 0.0 2.25 1.0 1.83711730709 1
+       (3+1.5j) -1.5j (2.25+2.25j) (0.5-0.5j) (1.50768393746+1.04970907623j) -1
+       3/2 1 1.5 (1.5+0j)
 
+       7/2 -1/2 3 3/4 9/4 -1
+       3.0 0.0 2.25 1.0 1.83711730709 -1
+       3 0 9/4 1 1.83711730709 0
+       (3+1.5j) -1.5j (2.25+2.25j) (0.5-0.5j) (1.50768393746+1.04970907623j) -1
+       (1.5+1.5j) (1.5+1.5j)
 
-def test():
-       print Rat(-1L, 1)
-       print Rat(1, -1)
-       a = Rat(1, 10)
-       print int(a), long(a), float(a)
-       b = Rat(2, 5)
+       (3.5+1.5j) (-0.5+1.5j) (3+3j) (0.75+0.75j) 4.5j -1
+       (3+1.5j) 1.5j (2.25+2.25j) (1+1j) (1.18235814075+2.85446505899j) 1
+       (3+1.5j) 1.5j (2.25+2.25j) (1+1j) (1.18235814075+2.85446505899j) 1
+       (3+3j) 0j 4.5j (1+0j) (-0.638110484918+0.705394566962j) 0
+       '''
+       print rat(-1L, 1)
+       print rat(1, -1)
+       a = rat(1, 10)
+       print int(a), long(a), float(a), complex(a)
+       b = rat(2, 5)
        l = [a+b, a-b, a*b, a/b]
        print l
        l.sort()
        print l
-       print Rat(0, 1)
+       print rat(0, 1)
        print a+1
        print a+1L
        print a+1.0
        try:
-               print Rat(1, 0)
+               print rat(1, 0)
                raise SystemError, 'should have been ZeroDivisionError'
        except ZeroDivisionError:
                print 'OK'
+       print rat(2), rat(1.5), rat(3, 2), rat(1.5+1.5j), rat(31415926,10000000)
+       list = [2, 1.5, rat(3,2), 1.5+1.5j]
+       for i in list:
+               print i,
+               if type(i) is not ComplexType:
+                       print int(i), float(i),
+               print complex(i)
+               print
+               for j in list:
+                       print i + j, i - j, i * j, i / j, i ** j, cmp(i, j)
 
-test()
+if __name__ == '__main__':
+    test()