From 0609f191bc3f22af862696cd0002449bd48acb8d Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Tue, 13 May 1997 19:25:57 +0000 Subject: A completely new Rat.py by Sjoerd. --- Demo/classes/Rat.py | 316 ++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 260 insertions(+), 56 deletions(-) diff --git a/Demo/classes/Rat.py b/Demo/classes/Rat.py index 7553745..5273e32 100755 --- a/Demo/classes/Rat.py +++ b/Demo/classes/Rat.py @@ -1,103 +1,307 @@ -# 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() -- cgit v0.12