summaryrefslogtreecommitdiffstats
path: root/Demo/classes/Rat.py
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>1997-05-13 19:25:57 (GMT)
committerGuido van Rossum <guido@python.org>1997-05-13 19:25:57 (GMT)
commit0609f191bc3f22af862696cd0002449bd48acb8d (patch)
treed9243c3d70c5b7c64208314ca344af29810e4269 /Demo/classes/Rat.py
parente0332c71737f85dd616bf5aa0a9141e466c82cc0 (diff)
downloadcpython-0609f191bc3f22af862696cd0002449bd48acb8d.zip
cpython-0609f191bc3f22af862696cd0002449bd48acb8d.tar.gz
cpython-0609f191bc3f22af862696cd0002449bd48acb8d.tar.bz2
A completely new Rat.py by Sjoerd.
Diffstat (limited to 'Demo/classes/Rat.py')
-rwxr-xr-xDemo/classes/Rat.py316
1 files 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()