# Commits

committed ba005e4

A completely new Rat.py by Sjoerd.

• Participants
• Parent commits 5058166
• Branches legacy-trunk

# File Demo/classes/Rat.py

• Ignore whitespace
`-# Rational numbers`
`+'''\`
`+This module implements rational numbers.`
`+`
`+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.`
`+`
`+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 rat(num, den):`
`-	if type(num) == FloatType or type(den) == FloatType:`
`-		return num/den`
`-	return Rat(num, den)`
`-`
`-`
` 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`
`+		else:`
`+			return 0`
` `
`-	def __float__(self):`
`-		return float(self.num) / float(self.den)`
`+	def __rcmp__(b, a):`
`+		   return cmp(Rat(a), b)`
` `
`-	def __long__(self):`
`-		return long(self.num) / long(self.den)`
`+	# a != 0`
`+	def __nonzero__(a):`
`+		return a.__num != 0`
` `
`-	def __int__(self):`
`-		return int(self.num / self.den)`
`-`
`+	# 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'`
`-`
`-	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 __mul__(a, b):`
`-		return rat(a.num*b.num, a.den*b.den)`
`-`
`-	def __div__(a, b):`
`-		return rat(a.num*b.den, a.den*b.num)`
`-`
`-	def __neg__(self):`
`-		return rat(-self.num, self.den)`
`-`
`+		return a, Rat(b)`
` `
` 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)`
`+	'''\`
`+	Test function for rat module.`
`+`
`+	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)`
`+`
`+	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)`
`+`
`+	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)`
`+`
`+	(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()`