home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / pyos2bin.zip / Demo / classes / Rat.py < prev    next >
Text File  |  1997-05-13  |  7KB  |  308 lines

  1. '''\
  2. This module implements rational numbers.
  3.  
  4. The entry point of this module is the function
  5.     rat(numerator, denominator)
  6. If either numerator or denominator is of an integral or rational type,
  7. the result is a rational number, else, the result is the simplest of
  8. the types float and complex which can hold numerator/denominator.
  9. If denominator is omitted, it defaults to 1.
  10. Rational numbers can be used in calculations with any other numeric
  11. type.  The result of the calculation will be rational if possible.
  12.  
  13. There is also a test function with calling sequence
  14.     test()
  15. The documentation string of the test function contains the expected
  16. output.
  17. '''
  18.  
  19. # Contributed by Sjoerd Mullender
  20.  
  21. from types import *
  22.  
  23. def gcd(a, b):
  24.     '''Calculate the Greatest Common Divisor.'''
  25.     while b:
  26.         a, b = b, a%b
  27.     return a
  28.  
  29. def rat(num, den = 1):
  30.     # must check complex before float
  31.     if type(num) is ComplexType or type(den) is ComplexType:
  32.         # numerator or denominator is complex: return a complex
  33.         return complex(num) / complex(den)
  34.     if type(num) is FloatType or type(den) is FloatType:
  35.         # numerator or denominator is float: return a float
  36.         return float(num) / float(den)
  37.     # otherwise return a rational
  38.     return Rat(num, den)
  39.  
  40. class Rat:
  41.     '''This class implements rational numbers.'''
  42.  
  43.     def __init__(self, num, den = 1):
  44.         if den == 0:
  45.             raise ZeroDivisionError, 'rat(x, 0)'
  46.  
  47.         # normalize
  48.  
  49.         # must check complex before float
  50.         if type(num) is ComplexType or type(den) is ComplexType:
  51.             # numerator or denominator is complex:
  52.             # normalized form has denominator == 1+0j
  53.             self.__num = complex(num) / complex(den)
  54.             self.__den = complex(1)
  55.             return
  56.         if type(num) is FloatType or type(den) is FloatType:
  57.             # numerator or denominator is float:
  58.             # normalized form has denominator == 1.0
  59.             self.__num = float(num) / float(den)
  60.             self.__den = 1.0
  61.             return
  62.         if (type(num) is InstanceType and
  63.             num.__class__ is self.__class__) or \
  64.            (type(den) is InstanceType and
  65.             den.__class__ is self.__class__):
  66.             # numerator or denominator is rational
  67.             new = num / den
  68.             if type(new) is not InstanceType or \
  69.                new.__class__ is not self.__class__:
  70.                 self.__num = new
  71.                 if type(new) is ComplexType:
  72.                     self.__den = complex(1)
  73.                 else:
  74.                     self.__den = 1.0
  75.             else:
  76.                 self.__num = new.__num
  77.                 self.__den = new.__den
  78.         else:
  79.             # make sure numerator and denominator don't
  80.             # have common factors
  81.             # this also makes sure that denominator > 0
  82.             g = gcd(num, den)
  83.             self.__num = num / g
  84.             self.__den = den / g
  85.         # try making numerator and denominator of IntType if they fit
  86.         try:
  87.             numi = int(self.__num)
  88.             deni = int(self.__den)
  89.         except (OverflowError, TypeError):
  90.             pass
  91.         else:
  92.             if self.__num == numi and self.__den == deni:
  93.                 self.__num = numi
  94.                 self.__den = deni
  95.  
  96.     def __repr__(self):
  97.         return 'Rat(%s,%s)' % (self.__num, self.__den)
  98.  
  99.     def __str__(self):
  100.         if self.__den == 1:
  101.             return str(self.__num)
  102.         else:
  103.             return '%s/%s' % (str(self.__num), str(self.__den))
  104.  
  105.     # a + b
  106.     def __add__(a, b):
  107.         try:
  108.             return rat(a.__num * b.__den + b.__num * a.__den,
  109.                    a.__den * b.__den)
  110.         except OverflowError:
  111.             return rat(long(a.__num) * long(b.__den) +
  112.                    long(b.__num) * long(a.__den),
  113.                    long(a.__den) * long(b.__den))
  114.  
  115.     def __radd__(b, a):
  116.         return Rat(a) + b
  117.  
  118.     # a - b
  119.     def __sub__(a, b):
  120.         try:
  121.             return rat(a.__num * b.__den - b.__num * a.__den,
  122.                    a.__den * b.__den)
  123.         except OverflowError:
  124.             return rat(long(a.__num) * long(b.__den) -
  125.                    long(b.__num) * long(a.__den),
  126.                    long(a.__den) * long(b.__den))
  127.  
  128.     def __rsub__(b, a):
  129.         return Rat(a) - b
  130.  
  131.     # a * b
  132.     def __mul__(a, b):
  133.         try:
  134.             return rat(a.__num * b.__num, a.__den * b.__den)
  135.         except OverflowError:
  136.             return rat(long(a.__num) * long(b.__num),
  137.                    long(a.__den) * long(b.__den))
  138.  
  139.     def __rmul__(b, a):
  140.         return Rat(a) * b
  141.  
  142.     # a / b
  143.     def __div__(a, b):
  144.         try:
  145.             return rat(a.__num * b.__den, a.__den * b.__num)
  146.         except OverflowError:
  147.             return rat(long(a.__num) * long(b.__den),
  148.                    long(a.__den) * long(b.__num))
  149.  
  150.     def __rdiv__(b, a):
  151.         return Rat(a) / b
  152.  
  153.     # a % b
  154.     def __mod__(a, b):
  155.         div = a / b
  156.         try:
  157.             div = int(div)
  158.         except OverflowError:
  159.             div = long(div)
  160.         return a - b * div
  161.  
  162.     def __rmod__(b, a):
  163.         return Rat(a) % b
  164.  
  165.     # a ** b
  166.     def __pow__(a, b):
  167.         if b.__den != 1:
  168.             if type(a.__num) is ComplexType:
  169.                 a = complex(a)
  170.             else:
  171.                 a = float(a)
  172.             if type(b.__num) is ComplexType:
  173.                 b = complex(b)
  174.             else:
  175.                 b = float(b)
  176.             return a ** b
  177.         try:
  178.             return rat(a.__num ** b.__num, a.__den ** b.__num)
  179.         except OverflowError:
  180.             return rat(long(a.__num) ** b.__num,
  181.                    long(a.__den) ** b.__num)
  182.  
  183.     def __rpow__(b, a):
  184.         return Rat(a) ** b
  185.  
  186.     # -a
  187.     def __neg__(a):
  188.         try:
  189.             return rat(-a.__num, a.__den)
  190.         except OverflowError:
  191.             # a.__num == sys.maxint
  192.             return rat(-long(a.__num), a.__den)
  193.  
  194.     # abs(a)
  195.     def __abs__(a):
  196.         return rat(abs(a.__num), a.__den)
  197.  
  198.     # int(a)
  199.     def __int__(a):
  200.         return int(a.__num / a.__den)
  201.  
  202.     # long(a)
  203.     def __long__(a):
  204.         return long(a.__num) / long(a.__den)
  205.  
  206.     # float(a)
  207.     def __float__(a):
  208.         return float(a.__num) / float(a.__den)
  209.  
  210.     # complex(a)
  211.     def __complex__(a):
  212.         return complex(a.__num) / complex(a.__den)
  213.  
  214.     # cmp(a,b)
  215.     def __cmp__(a, b):
  216.         diff = a - b
  217.         if diff.__num < 0:
  218.             return -1
  219.         elif diff.__num > 0:
  220.             return 1
  221.         else:
  222.             return 0
  223.  
  224.     def __rcmp__(b, a):
  225.            return cmp(Rat(a), b)
  226.  
  227.     # a != 0
  228.     def __nonzero__(a):
  229.         return a.__num != 0
  230.  
  231.     # coercion
  232.     def __coerce__(a, b):
  233.         return a, Rat(b)
  234.  
  235. def test():
  236.     '''\
  237.     Test function for rat module.
  238.  
  239.     The expected output is (module some differences in floating
  240.     precission):
  241.     -1
  242.     -1
  243.     0 0L 0.1 (0.1+0j)
  244.     [Rat(1,2), Rat(-3,10), Rat(1,25), Rat(1,4)]
  245.     [Rat(-3,10), Rat(1,25), Rat(1,4), Rat(1,2)]
  246.     0
  247.     11/10
  248.     11/10
  249.     1.1
  250.     OK
  251.     2 1.5 3/2 (1.5+1.5j) 15707963/5000000
  252.     2 2 2.0 (2+0j)
  253.  
  254.     4 0 4 1 4 0
  255.     3.5 0.5 3.0 1.33333333333 2.82842712475 1
  256.     7/2 1/2 3 4/3 2.82842712475 1
  257.     (3.5+1.5j) (0.5-1.5j) (3+3j) (0.666666666667-0.666666666667j) (1.43248815986+2.43884761145j) 1
  258.     1.5 1 1.5 (1.5+0j)
  259.  
  260.     3.5 -0.5 3.0 0.75 2.25 -1
  261.     3.0 0.0 2.25 1.0 1.83711730709 0
  262.     3.0 0.0 2.25 1.0 1.83711730709 1
  263.     (3+1.5j) -1.5j (2.25+2.25j) (0.5-0.5j) (1.50768393746+1.04970907623j) -1
  264.     3/2 1 1.5 (1.5+0j)
  265.  
  266.     7/2 -1/2 3 3/4 9/4 -1
  267.     3.0 0.0 2.25 1.0 1.83711730709 -1
  268.     3 0 9/4 1 1.83711730709 0
  269.     (3+1.5j) -1.5j (2.25+2.25j) (0.5-0.5j) (1.50768393746+1.04970907623j) -1
  270.     (1.5+1.5j) (1.5+1.5j)
  271.  
  272.     (3.5+1.5j) (-0.5+1.5j) (3+3j) (0.75+0.75j) 4.5j -1
  273.     (3+1.5j) 1.5j (2.25+2.25j) (1+1j) (1.18235814075+2.85446505899j) 1
  274.     (3+1.5j) 1.5j (2.25+2.25j) (1+1j) (1.18235814075+2.85446505899j) 1
  275.     (3+3j) 0j 4.5j (1+0j) (-0.638110484918+0.705394566962j) 0
  276.     '''
  277.     print rat(-1L, 1)
  278.     print rat(1, -1)
  279.     a = rat(1, 10)
  280.     print int(a), long(a), float(a), complex(a)
  281.     b = rat(2, 5)
  282.     l = [a+b, a-b, a*b, a/b]
  283.     print l
  284.     l.sort()
  285.     print l
  286.     print rat(0, 1)
  287.     print a+1
  288.     print a+1L
  289.     print a+1.0
  290.     try:
  291.         print rat(1, 0)
  292.         raise SystemError, 'should have been ZeroDivisionError'
  293.     except ZeroDivisionError:
  294.         print 'OK'
  295.     print rat(2), rat(1.5), rat(3, 2), rat(1.5+1.5j), rat(31415926,10000000)
  296.     list = [2, 1.5, rat(3,2), 1.5+1.5j]
  297.     for i in list:
  298.         print i,
  299.         if type(i) is not ComplexType:
  300.             print int(i), float(i),
  301.         print complex(i)
  302.         print
  303.         for j in list:
  304.             print i + j, i - j, i * j, i / j, i ** j, cmp(i, j)
  305.  
  306. if __name__ == '__main__':
  307.     test()
  308.