+++ /dev/null
-# Complex numbers\r
-# ---------------\r
-\r
-# [Now that Python has a complex data type built-in, this is not very\r
-# useful, but it's still a nice example class]\r
-\r
-# This module represents complex numbers as instances of the class Complex.\r
-# A Complex instance z has two data attribues, z.re (the real part) and z.im\r
-# (the imaginary part). In fact, z.re and z.im can have any value -- all\r
-# arithmetic operators work regardless of the type of z.re and z.im (as long\r
-# as they support numerical operations).\r
-#\r
-# The following functions exist (Complex is actually a class):\r
-# Complex([re [,im]) -> creates a complex number from a real and an imaginary part\r
-# IsComplex(z) -> true iff z is a complex number (== has .re and .im attributes)\r
-# ToComplex(z) -> a complex number equal to z; z itself if IsComplex(z) is true\r
-# if z is a tuple(re, im) it will also be converted\r
-# PolarToComplex([r [,phi [,fullcircle]]]) ->\r
-# the complex number z for which r == z.radius() and phi == z.angle(fullcircle)\r
-# (r and phi default to 0)\r
-# exp(z) -> returns the complex exponential of z. Equivalent to pow(math.e,z).\r
-#\r
-# Complex numbers have the following methods:\r
-# z.abs() -> absolute value of z\r
-# z.radius() == z.abs()\r
-# z.angle([fullcircle]) -> angle from positive X axis; fullcircle gives units\r
-# z.phi([fullcircle]) == z.angle(fullcircle)\r
-#\r
-# These standard functions and unary operators accept complex arguments:\r
-# abs(z)\r
-# -z\r
-# +z\r
-# not z\r
-# repr(z) == `z`\r
-# str(z)\r
-# hash(z) -> a combination of hash(z.re) and hash(z.im) such that if z.im is zero\r
-# the result equals hash(z.re)\r
-# Note that hex(z) and oct(z) are not defined.\r
-#\r
-# These conversions accept complex arguments only if their imaginary part is zero:\r
-# int(z)\r
-# long(z)\r
-# float(z)\r
-#\r
-# The following operators accept two complex numbers, or one complex number\r
-# and one real number (int, long or float):\r
-# z1 + z2\r
-# z1 - z2\r
-# z1 * z2\r
-# z1 / z2\r
-# pow(z1, z2)\r
-# cmp(z1, z2)\r
-# Note that z1 % z2 and divmod(z1, z2) are not defined,\r
-# nor are shift and mask operations.\r
-#\r
-# The standard module math does not support complex numbers.\r
-# The cmath modules should be used instead.\r
-#\r
-# Idea:\r
-# add a class Polar(r, phi) and mixed-mode arithmetic which\r
-# chooses the most appropriate type for the result:\r
-# Complex for +,-,cmp\r
-# Polar for *,/,pow\r
-\r
-import math\r
-import sys\r
-\r
-twopi = math.pi*2.0\r
-halfpi = math.pi/2.0\r
-\r
-def IsComplex(obj):\r
- return hasattr(obj, 're') and hasattr(obj, 'im')\r
-\r
-def ToComplex(obj):\r
- if IsComplex(obj):\r
- return obj\r
- elif isinstance(obj, tuple):\r
- return Complex(*obj)\r
- else:\r
- return Complex(obj)\r
-\r
-def PolarToComplex(r = 0, phi = 0, fullcircle = twopi):\r
- phi = phi * (twopi / fullcircle)\r
- return Complex(math.cos(phi)*r, math.sin(phi)*r)\r
-\r
-def Re(obj):\r
- if IsComplex(obj):\r
- return obj.re\r
- return obj\r
-\r
-def Im(obj):\r
- if IsComplex(obj):\r
- return obj.im\r
- return 0\r
-\r
-class Complex:\r
-\r
- def __init__(self, re=0, im=0):\r
- _re = 0\r
- _im = 0\r
- if IsComplex(re):\r
- _re = re.re\r
- _im = re.im\r
- else:\r
- _re = re\r
- if IsComplex(im):\r
- _re = _re - im.im\r
- _im = _im + im.re\r
- else:\r
- _im = _im + im\r
- # this class is immutable, so setting self.re directly is\r
- # not possible.\r
- self.__dict__['re'] = _re\r
- self.__dict__['im'] = _im\r
-\r
- def __setattr__(self, name, value):\r
- raise TypeError, 'Complex numbers are immutable'\r
-\r
- def __hash__(self):\r
- if not self.im:\r
- return hash(self.re)\r
- return hash((self.re, self.im))\r
-\r
- def __repr__(self):\r
- if not self.im:\r
- return 'Complex(%r)' % (self.re,)\r
- else:\r
- return 'Complex(%r, %r)' % (self.re, self.im)\r
-\r
- def __str__(self):\r
- if not self.im:\r
- return repr(self.re)\r
- else:\r
- return 'Complex(%r, %r)' % (self.re, self.im)\r
-\r
- def __neg__(self):\r
- return Complex(-self.re, -self.im)\r
-\r
- def __pos__(self):\r
- return self\r
-\r
- def __abs__(self):\r
- return math.hypot(self.re, self.im)\r
-\r
- def __int__(self):\r
- if self.im:\r
- raise ValueError, "can't convert Complex with nonzero im to int"\r
- return int(self.re)\r
-\r
- def __long__(self):\r
- if self.im:\r
- raise ValueError, "can't convert Complex with nonzero im to long"\r
- return long(self.re)\r
-\r
- def __float__(self):\r
- if self.im:\r
- raise ValueError, "can't convert Complex with nonzero im to float"\r
- return float(self.re)\r
-\r
- def __cmp__(self, other):\r
- other = ToComplex(other)\r
- return cmp((self.re, self.im), (other.re, other.im))\r
-\r
- def __rcmp__(self, other):\r
- other = ToComplex(other)\r
- return cmp(other, self)\r
-\r
- def __nonzero__(self):\r
- return not (self.re == self.im == 0)\r
-\r
- abs = radius = __abs__\r
-\r
- def angle(self, fullcircle = twopi):\r
- return (fullcircle/twopi) * ((halfpi - math.atan2(self.re, self.im)) % twopi)\r
-\r
- phi = angle\r
-\r
- def __add__(self, other):\r
- other = ToComplex(other)\r
- return Complex(self.re + other.re, self.im + other.im)\r
-\r
- __radd__ = __add__\r
-\r
- def __sub__(self, other):\r
- other = ToComplex(other)\r
- return Complex(self.re - other.re, self.im - other.im)\r
-\r
- def __rsub__(self, other):\r
- other = ToComplex(other)\r
- return other - self\r
-\r
- def __mul__(self, other):\r
- other = ToComplex(other)\r
- return Complex(self.re*other.re - self.im*other.im,\r
- self.re*other.im + self.im*other.re)\r
-\r
- __rmul__ = __mul__\r
-\r
- def __div__(self, other):\r
- other = ToComplex(other)\r
- d = float(other.re*other.re + other.im*other.im)\r
- if not d: raise ZeroDivisionError, 'Complex division'\r
- return Complex((self.re*other.re + self.im*other.im) / d,\r
- (self.im*other.re - self.re*other.im) / d)\r
-\r
- def __rdiv__(self, other):\r
- other = ToComplex(other)\r
- return other / self\r
-\r
- def __pow__(self, n, z=None):\r
- if z is not None:\r
- raise TypeError, 'Complex does not support ternary pow()'\r
- if IsComplex(n):\r
- if n.im:\r
- if self.im: raise TypeError, 'Complex to the Complex power'\r
- else: return exp(math.log(self.re)*n)\r
- n = n.re\r
- r = pow(self.abs(), n)\r
- phi = n*self.angle()\r
- return Complex(math.cos(phi)*r, math.sin(phi)*r)\r
-\r
- def __rpow__(self, base):\r
- base = ToComplex(base)\r
- return pow(base, self)\r
-\r
-def exp(z):\r
- r = math.exp(z.re)\r
- return Complex(math.cos(z.im)*r,math.sin(z.im)*r)\r
-\r
-\r
-def checkop(expr, a, b, value, fuzz = 1e-6):\r
- print ' ', a, 'and', b,\r
- try:\r
- result = eval(expr)\r
- except:\r
- result = sys.exc_type\r
- print '->', result\r
- if isinstance(result, str) or isinstance(value, str):\r
- ok = (result == value)\r
- else:\r
- ok = abs(result - value) <= fuzz\r
- if not ok:\r
- print '!!\t!!\t!! should be', value, 'diff', abs(result - value)\r
-\r
-def test():\r
- print 'test constructors'\r
- constructor_test = (\r
- # "expect" is an array [re,im] "got" the Complex.\r
- ( (0,0), Complex() ),\r
- ( (0,0), Complex() ),\r
- ( (1,0), Complex(1) ),\r
- ( (0,1), Complex(0,1) ),\r
- ( (1,2), Complex(Complex(1,2)) ),\r
- ( (1,3), Complex(Complex(1,2),1) ),\r
- ( (0,0), Complex(0,Complex(0,0)) ),\r
- ( (3,4), Complex(3,Complex(4)) ),\r
- ( (-1,3), Complex(1,Complex(3,2)) ),\r
- ( (-7,6), Complex(Complex(1,2),Complex(4,8)) ) )\r
- cnt = [0,0]\r
- for t in constructor_test:\r
- cnt[0] += 1\r
- if ((t[0][0]!=t[1].re)or(t[0][1]!=t[1].im)):\r
- print " expected", t[0], "got", t[1]\r
- cnt[1] += 1\r
- print " ", cnt[1], "of", cnt[0], "tests failed"\r
- # test operators\r
- testsuite = {\r
- 'a+b': [\r
- (1, 10, 11),\r
- (1, Complex(0,10), Complex(1,10)),\r
- (Complex(0,10), 1, Complex(1,10)),\r
- (Complex(0,10), Complex(1), Complex(1,10)),\r
- (Complex(1), Complex(0,10), Complex(1,10)),\r
- ],\r
- 'a-b': [\r
- (1, 10, -9),\r
- (1, Complex(0,10), Complex(1,-10)),\r
- (Complex(0,10), 1, Complex(-1,10)),\r
- (Complex(0,10), Complex(1), Complex(-1,10)),\r
- (Complex(1), Complex(0,10), Complex(1,-10)),\r
- ],\r
- 'a*b': [\r
- (1, 10, 10),\r
- (1, Complex(0,10), Complex(0, 10)),\r
- (Complex(0,10), 1, Complex(0,10)),\r
- (Complex(0,10), Complex(1), Complex(0,10)),\r
- (Complex(1), Complex(0,10), Complex(0,10)),\r
- ],\r
- 'a/b': [\r
- (1., 10, 0.1),\r
- (1, Complex(0,10), Complex(0, -0.1)),\r
- (Complex(0, 10), 1, Complex(0, 10)),\r
- (Complex(0, 10), Complex(1), Complex(0, 10)),\r
- (Complex(1), Complex(0,10), Complex(0, -0.1)),\r
- ],\r
- 'pow(a,b)': [\r
- (1, 10, 1),\r
- (1, Complex(0,10), 1),\r
- (Complex(0,10), 1, Complex(0,10)),\r
- (Complex(0,10), Complex(1), Complex(0,10)),\r
- (Complex(1), Complex(0,10), 1),\r
- (2, Complex(4,0), 16),\r
- ],\r
- 'cmp(a,b)': [\r
- (1, 10, -1),\r
- (1, Complex(0,10), 1),\r
- (Complex(0,10), 1, -1),\r
- (Complex(0,10), Complex(1), -1),\r
- (Complex(1), Complex(0,10), 1),\r
- ],\r
- }\r
- for expr in sorted(testsuite):\r
- print expr + ':'\r
- t = (expr,)\r
- for item in testsuite[expr]:\r
- checkop(*(t+item))\r
-\r
-\r
-if __name__ == '__main__':\r
- test()\r