4 # This module represents complex numbers as instances of the class Complex.
5 # A Complex instance z has two data attribues, z.re (the real part) and z.im
6 # (the imaginary part). In fact, z.re and z.im can have any value -- all
7 # arithmetic operators work regardless of the type of z.re and z.im (as long
8 # as they support numerical operations).
10 # The following functions exist (Complex is actually a class):
11 # Complex([re [,im]) -> creates a complex number from a real and an imaginary part
12 # IsComplex(z) -> true iff z is a complex number (== has .re and .im attributes)
13 # Polar([r [,phi [,fullcircle]]]) ->
14 # the complex number z for which r == z.radius() and phi == z.angle(fullcircle)
15 # (r and phi default to 0)
17 # Complex numbers have the following methods:
18 # z.abs() -> absolute value of z
19 # z.radius() == z.abs()
20 # z.angle([fullcircle]) -> angle from positive X axis; fullcircle gives units
21 # z.phi([fullcircle]) == z.angle(fullcircle)
23 # These standard functions and unary operators accept complex arguments:
30 # hash(z) -> a combination of hash(z.re) and hash(z.im) such that if z.im is zero
31 # the result equals hash(z.re)
32 # Note that hex(z) and oct(z) are not defined.
34 # These conversions accept complex arguments only if their imaginary part is zero:
39 # The following operators accept two complex numbers, or one complex number
40 # and one real number (int, long or float):
47 # Note that z1 % z2 and divmod(z1, z2) are not defined,
48 # nor are shift and mask operations.
50 # The standard module math does not support complex numbers.
51 # (I suppose it would be easy to implement a cmath module.)
54 # add a class Polar(r, phi) and mixed-mode arithmetic which
55 # chooses the most appropriate type for the result:
62 if not hasattr(math
, 'hypot'):
64 # XXX I know there's a way to compute this without possibly causing
65 # overflow, but I can't remember what it is right now...
66 return math
.sqrt(x
*x
+ y
*y
)
73 return hasattr(obj
, 're') and hasattr(obj
, 'im')
75 def Polar(r
= 0, phi
= 0, fullcircle
= twopi
):
76 phi
= phi
* (twopi
/ fullcircle
)
77 return Complex(math
.cos(phi
)*r
, math
.sin(phi
)*r
)
81 def __init__(self
, re
=0, im
=0):
91 def __setattr__(self
, name
, value
):
92 if hasattr(self
, name
):
93 raise TypeError, "Complex numbers have set-once attributes"
94 self
.__dict
__[name
] = value
98 return 'Complex(%s)' % `self
.re`
100 return 'Complex(%s, %s)' % (`self
.re`
, `self
.im`
)
106 return 'Complex(%s, %s)' % (`self
.re`
, `self
.im`
)
108 def __coerce__(self
, other
):
111 return self
, Complex(other
) # May fail
113 def __cmp__(self
, other
):
114 return cmp(self
.re
, other
.re
) or cmp(self
.im
, other
.im
)
117 if not self
.im
: return hash(self
.re
)
118 mod
= sys
.maxint
+ 1L
119 return int((hash(self
.re
) + 2L*hash(self
.im
) + mod
) % (2L*mod
) - mod
)
122 return Complex(-self
.re
, -self
.im
)
128 return math
.hypot(self
.re
, self
.im
)
129 ##return math.sqrt(self.re*self.re + self.im*self.im)
134 raise ValueError, "can't convert Complex with nonzero im to int"
139 raise ValueError, "can't convert Complex with nonzero im to long"
144 raise ValueError, "can't convert Complex with nonzero im to float"
145 return float(self
.re
)
147 def __nonzero__(self
):
148 return not (self
.re
== self
.im
== 0)
150 abs = radius
= __abs__
152 def angle(self
, fullcircle
= twopi
):
153 return (fullcircle
/twopi
) * ((halfpi
- math
.atan2(self
.re
, self
.im
)) % twopi
)
157 def __add__(self
, other
):
158 return Complex(self
.re
+ other
.re
, self
.im
+ other
.im
)
162 def __sub__(self
, other
):
163 return Complex(self
.re
- other
.re
, self
.im
- other
.im
)
165 def __rsub__(self
, other
):
166 return Complex(other
.re
- self
.re
, other
.im
- self
.im
)
168 def __mul__(self
, other
):
169 return Complex(self
.re
*other
.re
- self
.im
*other
.im
,
170 self
.re
*other
.im
+ self
.im
*other
.re
)
174 def __div__(self
, other
):
175 # Deviating from the general principle of not forcing re or im
176 # to be floats, we cast to float here, otherwise division
177 # of Complex numbers with integer re and im parts would use
178 # the (truncating) integer division
179 d
= float(other
.re
*other
.re
+ other
.im
*other
.im
)
180 if not d
: raise ZeroDivisionError, 'Complex division'
181 return Complex((self
.re
*other
.re
+ self
.im
*other
.im
) / d
,
182 (self
.im
*other
.re
- self
.re
*other
.im
) / d
)
184 def __rdiv__(self
, other
):
187 def __pow__(self
, n
, z
=None):
189 raise TypeError, 'Complex does not support ternary pow()'
191 if n
.im
: raise TypeError, 'Complex to the Complex power'
193 r
= pow(self
.abs(), n
)
195 return Complex(math
.cos(phi
)*r
, math
.sin(phi
)*r
)
197 def __rpow__(self
, base
):
198 return pow(base
, self
)
201 # Everything below this point is part of the test suite
203 def checkop(expr
, a
, b
, value
, fuzz
= 1e-6):
205 print ' ', a
, 'and', b
,
209 result
= sys
.exc_type
211 if (type(result
) == type('') or type(value
) == type('')):
214 ok
= abs(result
- value
) <= fuzz
216 print '!!\t!!\t!! should be', value
, 'diff', abs(result
- value
)
223 (1, Complex(0,10), Complex(1,10)),
224 (Complex(0,10), 1, Complex(1,10)),
225 (Complex(0,10), Complex(1), Complex(1,10)),
226 (Complex(1), Complex(0,10), Complex(1,10)),
230 (1, Complex(0,10), Complex(1,-10)),
231 (Complex(0,10), 1, Complex(-1,10)),
232 (Complex(0,10), Complex(1), Complex(-1,10)),
233 (Complex(1), Complex(0,10), Complex(1,-10)),
237 (1, Complex(0,10), Complex(0, 10)),
238 (Complex(0,10), 1, Complex(0,10)),
239 (Complex(0,10), Complex(1), Complex(0,10)),
240 (Complex(1), Complex(0,10), Complex(0,10)),
244 (1, Complex(0,10), Complex(0, -0.1)),
245 (Complex(0, 10), 1, Complex(0, 10)),
246 (Complex(0, 10), Complex(1), Complex(0, 10)),
247 (Complex(1), Complex(0,10), Complex(0, -0.1)),
251 (1, Complex(0,10), 'TypeError'),
252 (Complex(0,10), 1, Complex(0,10)),
253 (Complex(0,10), Complex(1), Complex(0,10)),
254 (Complex(1), Complex(0,10), 'TypeError'),
255 (2, Complex(4,0), 16),
259 (1, Complex(0,10), 1),
260 (Complex(0,10), 1, -1),
261 (Complex(0,10), Complex(1), -1),
262 (Complex(1), Complex(0,10), 1),
265 exprs
= testsuite
.keys()
270 for item
in testsuite
[expr
]:
271 apply(checkop
, t
+item
)
274 if __name__
== '__main__':