4 # [Now that Python has a complex data type built-in, this is not very
5 # useful, but it's still a nice example class]
7 # This module represents complex numbers as instances of the class Complex.
8 # A Complex instance z has two data attribues, z.re (the real part) and z.im
9 # (the imaginary part). In fact, z.re and z.im can have any value -- all
10 # arithmetic operators work regardless of the type of z.re and z.im (as long
11 # as they support numerical operations).
13 # The following functions exist (Complex is actually a class):
14 # Complex([re [,im]) -> creates a complex number from a real and an imaginary part
15 # IsComplex(z) -> true iff z is a complex number (== has .re and .im attributes)
16 # ToComplex(z) -> a complex number equal to z; z itself if IsComplex(z) is true
17 # if z is a tuple(re, im) it will also be converted
18 # PolarToComplex([r [,phi [,fullcircle]]]) ->
19 # the complex number z for which r == z.radius() and phi == z.angle(fullcircle)
20 # (r and phi default to 0)
21 # exp(z) -> returns the complex exponential of z. Equivalent to pow(math.e,z).
23 # Complex numbers have the following methods:
24 # z.abs() -> absolute value of z
25 # z.radius() == z.abs()
26 # z.angle([fullcircle]) -> angle from positive X axis; fullcircle gives units
27 # z.phi([fullcircle]) == z.angle(fullcircle)
29 # These standard functions and unary operators accept complex arguments:
36 # hash(z) -> a combination of hash(z.re) and hash(z.im) such that if z.im is zero
37 # the result equals hash(z.re)
38 # Note that hex(z) and oct(z) are not defined.
40 # These conversions accept complex arguments only if their imaginary part is zero:
45 # The following operators accept two complex numbers, or one complex number
46 # and one real number (int, long or float):
53 # Note that z1 % z2 and divmod(z1, z2) are not defined,
54 # nor are shift and mask operations.
56 # The standard module math does not support complex numbers.
57 # (I suppose it would be easy to implement a cmath module.)
60 # add a class Polar(r, phi) and mixed-mode arithmetic which
61 # chooses the most appropriate type for the result:
72 return hasattr(obj
, 're') and hasattr(obj
, 'im')
77 elif type(obj
) == types
.TupleType
:
78 return apply(Complex
, obj
)
82 def PolarToComplex(r
= 0, phi
= 0, fullcircle
= twopi
):
83 phi
= phi
* (twopi
/ fullcircle
)
84 return Complex(math
.cos(phi
)*r
, math
.sin(phi
)*r
)
100 def __init__(self
, re
=0, im
=0):
102 im
= i
+ Complex(0, re
.im
)
107 self
.__dict
__['re'] = re
108 self
.__dict
__['im'] = im
110 def __setattr__(self
, name
, value
):
111 raise TypeError, 'Complex numbers are immutable'
114 if not self
.im
: return hash(self
.re
)
115 mod
= sys
.maxint
+ 1L
116 return int((hash(self
.re
) + 2L*hash(self
.im
) + mod
) % (2L*mod
) - mod
)
120 return 'Complex(%s)' % `self
.re`
122 return 'Complex(%s, %s)' % (`self
.re`
, `self
.im`
)
128 return 'Complex(%s, %s)' % (`self
.re`
, `self
.im`
)
131 return Complex(-self
.re
, -self
.im
)
137 # XXX could be done differently to avoid overflow!
138 return math
.sqrt(self
.re
*self
.re
+ self
.im
*self
.im
)
142 raise ValueError, "can't convert Complex with nonzero im to int"
147 raise ValueError, "can't convert Complex with nonzero im to long"
152 raise ValueError, "can't convert Complex with nonzero im to float"
153 return float(self
.re
)
155 def __cmp__(self
, other
):
156 other
= ToComplex(other
)
157 return cmp((self
.re
, self
.im
), (other
.re
, other
.im
))
159 def __rcmp__(self
, other
):
160 other
= ToComplex(other
)
161 return cmp(other
, self
)
163 def __nonzero__(self
):
164 return not (self
.re
== self
.im
== 0)
166 abs = radius
= __abs__
168 def angle(self
, fullcircle
= twopi
):
169 return (fullcircle
/twopi
) * ((halfpi
- math
.atan2(self
.re
, self
.im
)) % twopi
)
173 def __add__(self
, other
):
174 other
= ToComplex(other
)
175 return Complex(self
.re
+ other
.re
, self
.im
+ other
.im
)
179 def __sub__(self
, other
):
180 other
= ToComplex(other
)
181 return Complex(self
.re
- other
.re
, self
.im
- other
.im
)
183 def __rsub__(self
, other
):
184 other
= ToComplex(other
)
187 def __mul__(self
, other
):
188 other
= ToComplex(other
)
189 return Complex(self
.re
*other
.re
- self
.im
*other
.im
,
190 self
.re
*other
.im
+ self
.im
*other
.re
)
194 def __div__(self
, other
):
195 other
= ToComplex(other
)
196 d
= float(other
.re
*other
.re
+ other
.im
*other
.im
)
197 if not d
: raise ZeroDivisionError, 'Complex division'
198 return Complex((self
.re
*other
.re
+ self
.im
*other
.im
) / d
,
199 (self
.im
*other
.re
- self
.re
*other
.im
) / d
)
201 def __rdiv__(self
, other
):
202 other
= ToComplex(other
)
205 def __pow__(self
, n
, z
=None):
207 raise TypeError, 'Complex does not support ternary pow()'
210 if self
.im
: raise TypeError, 'Complex to the Complex power'
211 else: return exp(math
.log(self
.re
)*n
)
213 r
= pow(self
.abs(), n
)
215 return Complex(math
.cos(phi
)*r
, math
.sin(phi
)*r
)
217 def __rpow__(self
, base
):
218 base
= ToComplex(base
)
219 return pow(base
, self
)
223 return Complex(math
.cos(z
.im
)*r
,math
.sin(z
.im
)*r
)
226 def checkop(expr
, a
, b
, value
, fuzz
= 1e-6):
228 print ' ', a
, 'and', b
,
232 result
= sys
.exc_type
234 if (type(result
) == type('') or type(value
) == type('')):
237 ok
= abs(result
- value
) <= fuzz
239 print '!!\t!!\t!! should be', value
, 'diff', abs(result
- value
)
246 (1, Complex(0,10), Complex(1,10)),
247 (Complex(0,10), 1, Complex(1,10)),
248 (Complex(0,10), Complex(1), Complex(1,10)),
249 (Complex(1), Complex(0,10), Complex(1,10)),
253 (1, Complex(0,10), Complex(1,-10)),
254 (Complex(0,10), 1, Complex(-1,10)),
255 (Complex(0,10), Complex(1), Complex(-1,10)),
256 (Complex(1), Complex(0,10), Complex(1,-10)),
260 (1, Complex(0,10), Complex(0, 10)),
261 (Complex(0,10), 1, Complex(0,10)),
262 (Complex(0,10), Complex(1), Complex(0,10)),
263 (Complex(1), Complex(0,10), Complex(0,10)),
267 (1, Complex(0,10), Complex(0, -0.1)),
268 (Complex(0, 10), 1, Complex(0, 10)),
269 (Complex(0, 10), Complex(1), Complex(0, 10)),
270 (Complex(1), Complex(0,10), Complex(0, -0.1)),
274 (1, Complex(0,10), 1),
275 (Complex(0,10), 1, Complex(0,10)),
276 (Complex(0,10), Complex(1), Complex(0,10)),
277 (Complex(1), Complex(0,10), 1),
278 (2, Complex(4,0), 16),
282 (1, Complex(0,10), 1),
283 (Complex(0,10), 1, -1),
284 (Complex(0,10), Complex(1), -1),
285 (Complex(1), Complex(0,10), 1),
288 exprs
= testsuite
.keys()
293 for item
in testsuite
[expr
]:
294 apply(checkop
, t
+item
)
297 if __name__
== '__main__':