Issue #5816:
[python.git] / Lib / test / test_complex.py
blob1ff710fb8747ead171cd17726fc4891a58222206
1 import unittest, os
2 from test import test_support
4 import warnings
5 warnings.filterwarnings(
6 "ignore",
7 category=DeprecationWarning,
8 message=".*complex divmod.*are deprecated"
11 from random import random
12 from math import atan2, isnan, copysign
14 INF = float("inf")
15 NAN = float("nan")
16 # These tests ensure that complex math does the right thing
18 class ComplexTest(unittest.TestCase):
20 def assertAlmostEqual(self, a, b):
21 if isinstance(a, complex):
22 if isinstance(b, complex):
23 unittest.TestCase.assertAlmostEqual(self, a.real, b.real)
24 unittest.TestCase.assertAlmostEqual(self, a.imag, b.imag)
25 else:
26 unittest.TestCase.assertAlmostEqual(self, a.real, b)
27 unittest.TestCase.assertAlmostEqual(self, a.imag, 0.)
28 else:
29 if isinstance(b, complex):
30 unittest.TestCase.assertAlmostEqual(self, a, b.real)
31 unittest.TestCase.assertAlmostEqual(self, 0., b.imag)
32 else:
33 unittest.TestCase.assertAlmostEqual(self, a, b)
35 def assertCloseAbs(self, x, y, eps=1e-9):
36 """Return true iff floats x and y "are close\""""
37 # put the one with larger magnitude second
38 if abs(x) > abs(y):
39 x, y = y, x
40 if y == 0:
41 return abs(x) < eps
42 if x == 0:
43 return abs(y) < eps
44 # check that relative difference < eps
45 self.assert_(abs((x-y)/y) < eps)
47 def assertFloatsAreIdentical(self, x, y):
48 """assert that floats x and y are identical, in the sense that:
49 (1) both x and y are nans, or
50 (2) both x and y are infinities, with the same sign, or
51 (3) both x and y are zeros, with the same sign, or
52 (4) x and y are both finite and nonzero, and x == y
54 """
55 msg = 'floats {!r} and {!r} are not identical'
57 if isnan(x) or isnan(y):
58 if isnan(x) and isnan(y):
59 return
60 elif x == y:
61 if x != 0.0:
62 return
63 # both zero; check that signs match
64 elif copysign(1.0, x) == copysign(1.0, y):
65 return
66 else:
67 msg += ': zeros have different signs'
68 self.fail(msg.format(x, y))
70 def assertClose(self, x, y, eps=1e-9):
71 """Return true iff complexes x and y "are close\""""
72 self.assertCloseAbs(x.real, y.real, eps)
73 self.assertCloseAbs(x.imag, y.imag, eps)
75 def assertIs(self, a, b):
76 self.assert_(a is b)
78 def check_div(self, x, y):
79 """Compute complex z=x*y, and check that z/x==y and z/y==x."""
80 z = x * y
81 if x != 0:
82 q = z / x
83 self.assertClose(q, y)
84 q = z.__div__(x)
85 self.assertClose(q, y)
86 q = z.__truediv__(x)
87 self.assertClose(q, y)
88 if y != 0:
89 q = z / y
90 self.assertClose(q, x)
91 q = z.__div__(y)
92 self.assertClose(q, x)
93 q = z.__truediv__(y)
94 self.assertClose(q, x)
96 def test_div(self):
97 simple_real = [float(i) for i in xrange(-5, 6)]
98 simple_complex = [complex(x, y) for x in simple_real for y in simple_real]
99 for x in simple_complex:
100 for y in simple_complex:
101 self.check_div(x, y)
103 # A naive complex division algorithm (such as in 2.0) is very prone to
104 # nonsense errors for these (overflows and underflows).
105 self.check_div(complex(1e200, 1e200), 1+0j)
106 self.check_div(complex(1e-200, 1e-200), 1+0j)
108 # Just for fun.
109 for i in xrange(100):
110 self.check_div(complex(random(), random()),
111 complex(random(), random()))
113 self.assertRaises(ZeroDivisionError, complex.__div__, 1+1j, 0+0j)
114 # FIXME: The following currently crashes on Alpha
115 # self.assertRaises(OverflowError, pow, 1e200+1j, 1e200+1j)
117 def test_truediv(self):
118 self.assertAlmostEqual(complex.__truediv__(2+0j, 1+1j), 1-1j)
119 self.assertRaises(ZeroDivisionError, complex.__truediv__, 1+1j, 0+0j)
121 def test_floordiv(self):
122 self.assertAlmostEqual(complex.__floordiv__(3+0j, 1.5+0j), 2)
123 self.assertRaises(ZeroDivisionError, complex.__floordiv__, 3+0j, 0+0j)
125 def test_coerce(self):
126 self.assertRaises(OverflowError, complex.__coerce__, 1+1j, 1L<<10000)
128 def test_richcompare(self):
129 self.assertRaises(OverflowError, complex.__eq__, 1+1j, 1L<<10000)
130 self.assertEqual(complex.__lt__(1+1j, None), NotImplemented)
131 self.assertIs(complex.__eq__(1+1j, 1+1j), True)
132 self.assertIs(complex.__eq__(1+1j, 2+2j), False)
133 self.assertIs(complex.__ne__(1+1j, 1+1j), False)
134 self.assertIs(complex.__ne__(1+1j, 2+2j), True)
135 self.assertRaises(TypeError, complex.__lt__, 1+1j, 2+2j)
136 self.assertRaises(TypeError, complex.__le__, 1+1j, 2+2j)
137 self.assertRaises(TypeError, complex.__gt__, 1+1j, 2+2j)
138 self.assertRaises(TypeError, complex.__ge__, 1+1j, 2+2j)
140 def test_mod(self):
141 self.assertRaises(ZeroDivisionError, (1+1j).__mod__, 0+0j)
143 a = 3.33+4.43j
144 try:
145 a % 0
146 except ZeroDivisionError:
147 pass
148 else:
149 self.fail("modulo parama can't be 0")
151 def test_divmod(self):
152 self.assertRaises(ZeroDivisionError, divmod, 1+1j, 0+0j)
154 def test_pow(self):
155 self.assertAlmostEqual(pow(1+1j, 0+0j), 1.0)
156 self.assertAlmostEqual(pow(0+0j, 2+0j), 0.0)
157 self.assertRaises(ZeroDivisionError, pow, 0+0j, 1j)
158 self.assertAlmostEqual(pow(1j, -1), 1/1j)
159 self.assertAlmostEqual(pow(1j, 200), 1)
160 self.assertRaises(ValueError, pow, 1+1j, 1+1j, 1+1j)
162 a = 3.33+4.43j
163 self.assertEqual(a ** 0j, 1)
164 self.assertEqual(a ** 0.+0.j, 1)
166 self.assertEqual(3j ** 0j, 1)
167 self.assertEqual(3j ** 0, 1)
169 try:
170 0j ** a
171 except ZeroDivisionError:
172 pass
173 else:
174 self.fail("should fail 0.0 to negative or complex power")
176 try:
177 0j ** (3-2j)
178 except ZeroDivisionError:
179 pass
180 else:
181 self.fail("should fail 0.0 to negative or complex power")
183 # The following is used to exercise certain code paths
184 self.assertEqual(a ** 105, a ** 105)
185 self.assertEqual(a ** -105, a ** -105)
186 self.assertEqual(a ** -30, a ** -30)
188 self.assertEqual(0.0j ** 0, 1)
190 b = 5.1+2.3j
191 self.assertRaises(ValueError, pow, a, b, 0)
193 def test_boolcontext(self):
194 for i in xrange(100):
195 self.assert_(complex(random() + 1e-6, random() + 1e-6))
196 self.assert_(not complex(0.0, 0.0))
198 def test_conjugate(self):
199 self.assertClose(complex(5.3, 9.8).conjugate(), 5.3-9.8j)
201 def test_constructor(self):
202 class OS:
203 def __init__(self, value): self.value = value
204 def __complex__(self): return self.value
205 class NS(object):
206 def __init__(self, value): self.value = value
207 def __complex__(self): return self.value
208 self.assertEqual(complex(OS(1+10j)), 1+10j)
209 self.assertEqual(complex(NS(1+10j)), 1+10j)
210 self.assertRaises(TypeError, complex, OS(None))
211 self.assertRaises(TypeError, complex, NS(None))
213 self.assertAlmostEqual(complex("1+10j"), 1+10j)
214 self.assertAlmostEqual(complex(10), 10+0j)
215 self.assertAlmostEqual(complex(10.0), 10+0j)
216 self.assertAlmostEqual(complex(10L), 10+0j)
217 self.assertAlmostEqual(complex(10+0j), 10+0j)
218 self.assertAlmostEqual(complex(1,10), 1+10j)
219 self.assertAlmostEqual(complex(1,10L), 1+10j)
220 self.assertAlmostEqual(complex(1,10.0), 1+10j)
221 self.assertAlmostEqual(complex(1L,10), 1+10j)
222 self.assertAlmostEqual(complex(1L,10L), 1+10j)
223 self.assertAlmostEqual(complex(1L,10.0), 1+10j)
224 self.assertAlmostEqual(complex(1.0,10), 1+10j)
225 self.assertAlmostEqual(complex(1.0,10L), 1+10j)
226 self.assertAlmostEqual(complex(1.0,10.0), 1+10j)
227 self.assertAlmostEqual(complex(3.14+0j), 3.14+0j)
228 self.assertAlmostEqual(complex(3.14), 3.14+0j)
229 self.assertAlmostEqual(complex(314), 314.0+0j)
230 self.assertAlmostEqual(complex(314L), 314.0+0j)
231 self.assertAlmostEqual(complex(3.14+0j, 0j), 3.14+0j)
232 self.assertAlmostEqual(complex(3.14, 0.0), 3.14+0j)
233 self.assertAlmostEqual(complex(314, 0), 314.0+0j)
234 self.assertAlmostEqual(complex(314L, 0L), 314.0+0j)
235 self.assertAlmostEqual(complex(0j, 3.14j), -3.14+0j)
236 self.assertAlmostEqual(complex(0.0, 3.14j), -3.14+0j)
237 self.assertAlmostEqual(complex(0j, 3.14), 3.14j)
238 self.assertAlmostEqual(complex(0.0, 3.14), 3.14j)
239 self.assertAlmostEqual(complex("1"), 1+0j)
240 self.assertAlmostEqual(complex("1j"), 1j)
241 self.assertAlmostEqual(complex(), 0)
242 self.assertAlmostEqual(complex("-1"), -1)
243 self.assertAlmostEqual(complex("+1"), +1)
244 self.assertAlmostEqual(complex("(1+2j)"), 1+2j)
245 self.assertAlmostEqual(complex("(1.3+2.2j)"), 1.3+2.2j)
246 self.assertAlmostEqual(complex("3.14+1J"), 3.14+1j)
247 self.assertAlmostEqual(complex(" ( +3.14-6J )"), 3.14-6j)
248 self.assertAlmostEqual(complex(" ( +3.14-J )"), 3.14-1j)
249 self.assertAlmostEqual(complex(" ( +3.14+j )"), 3.14+1j)
250 self.assertAlmostEqual(complex("J"), 1j)
251 self.assertAlmostEqual(complex("( j )"), 1j)
252 self.assertAlmostEqual(complex("+J"), 1j)
253 self.assertAlmostEqual(complex("( -j)"), -1j)
254 self.assertAlmostEqual(complex('1e-500'), 0.0 + 0.0j)
255 self.assertAlmostEqual(complex('-1e-500j'), 0.0 - 0.0j)
256 self.assertAlmostEqual(complex('-1e-500+1e-500j'), -0.0 + 0.0j)
258 class complex2(complex): pass
259 self.assertAlmostEqual(complex(complex2(1+1j)), 1+1j)
260 self.assertAlmostEqual(complex(real=17, imag=23), 17+23j)
261 self.assertAlmostEqual(complex(real=17+23j), 17+23j)
262 self.assertAlmostEqual(complex(real=17+23j, imag=23), 17+46j)
263 self.assertAlmostEqual(complex(real=1+2j, imag=3+4j), -3+5j)
265 # check that the sign of a zero in the real or imaginary part
266 # is preserved when constructing from two floats. (These checks
267 # are harmless on systems without support for signed zeros.)
268 def split_zeros(x):
269 """Function that produces different results for 0. and -0."""
270 return atan2(x, -1.)
272 self.assertEqual(split_zeros(complex(1., 0.).imag), split_zeros(0.))
273 self.assertEqual(split_zeros(complex(1., -0.).imag), split_zeros(-0.))
274 self.assertEqual(split_zeros(complex(0., 1.).real), split_zeros(0.))
275 self.assertEqual(split_zeros(complex(-0., 1.).real), split_zeros(-0.))
277 c = 3.14 + 1j
278 self.assert_(complex(c) is c)
279 del c
281 self.assertRaises(TypeError, complex, "1", "1")
282 self.assertRaises(TypeError, complex, 1, "1")
284 if test_support.have_unicode:
285 self.assertEqual(complex(unicode(" 3.14+J ")), 3.14+1j)
287 # SF bug 543840: complex(string) accepts strings with \0
288 # Fixed in 2.3.
289 self.assertRaises(ValueError, complex, '1+1j\0j')
291 self.assertRaises(TypeError, int, 5+3j)
292 self.assertRaises(TypeError, long, 5+3j)
293 self.assertRaises(TypeError, float, 5+3j)
294 self.assertRaises(ValueError, complex, "")
295 self.assertRaises(TypeError, complex, None)
296 self.assertRaises(ValueError, complex, "\0")
297 self.assertRaises(ValueError, complex, "3\09")
298 self.assertRaises(TypeError, complex, "1", "2")
299 self.assertRaises(TypeError, complex, "1", 42)
300 self.assertRaises(TypeError, complex, 1, "2")
301 self.assertRaises(ValueError, complex, "1+")
302 self.assertRaises(ValueError, complex, "1+1j+1j")
303 self.assertRaises(ValueError, complex, "--")
304 self.assertRaises(ValueError, complex, "(1+2j")
305 self.assertRaises(ValueError, complex, "1+2j)")
306 self.assertRaises(ValueError, complex, "1+(2j)")
307 self.assertRaises(ValueError, complex, "(1+2j)123")
308 if test_support.have_unicode:
309 self.assertRaises(ValueError, complex, unicode("1"*500))
310 self.assertRaises(ValueError, complex, unicode("x"))
311 self.assertRaises(ValueError, complex, "1j+2")
312 self.assertRaises(ValueError, complex, "1e1ej")
313 self.assertRaises(ValueError, complex, "1e++1ej")
314 self.assertRaises(ValueError, complex, ")1+2j(")
315 # the following three are accepted by Python 2.6
316 self.assertRaises(ValueError, complex, "1..1j")
317 self.assertRaises(ValueError, complex, "1.11.1j")
318 self.assertRaises(ValueError, complex, "1e1.1j")
320 class EvilExc(Exception):
321 pass
323 class evilcomplex:
324 def __complex__(self):
325 raise EvilExc
327 self.assertRaises(EvilExc, complex, evilcomplex())
329 class float2:
330 def __init__(self, value):
331 self.value = value
332 def __float__(self):
333 return self.value
335 self.assertAlmostEqual(complex(float2(42.)), 42)
336 self.assertAlmostEqual(complex(real=float2(17.), imag=float2(23.)), 17+23j)
337 self.assertRaises(TypeError, complex, float2(None))
339 class complex0(complex):
340 """Test usage of __complex__() when inheriting from 'complex'"""
341 def __complex__(self):
342 return 42j
344 class complex1(complex):
345 """Test usage of __complex__() with a __new__() method"""
346 def __new__(self, value=0j):
347 return complex.__new__(self, 2*value)
348 def __complex__(self):
349 return self
351 class complex2(complex):
352 """Make sure that __complex__() calls fail if anything other than a
353 complex is returned"""
354 def __complex__(self):
355 return None
357 self.assertAlmostEqual(complex(complex0(1j)), 42j)
358 self.assertAlmostEqual(complex(complex1(1j)), 2j)
359 self.assertRaises(TypeError, complex, complex2(1j))
361 def test_hash(self):
362 for x in xrange(-30, 30):
363 self.assertEqual(hash(x), hash(complex(x, 0)))
364 x /= 3.0 # now check against floating point
365 self.assertEqual(hash(x), hash(complex(x, 0.)))
367 def test_abs(self):
368 nums = [complex(x/3., y/7.) for x in xrange(-9,9) for y in xrange(-9,9)]
369 for num in nums:
370 self.assertAlmostEqual((num.real**2 + num.imag**2) ** 0.5, abs(num))
372 def test_repr(self):
373 self.assertEqual(repr(1+6j), '(1+6j)')
374 self.assertEqual(repr(1-6j), '(1-6j)')
376 self.assertNotEqual(repr(-(1+0j)), '(-1+-0j)')
378 self.assertEqual(1-6j,complex(repr(1-6j)))
379 self.assertEqual(1+6j,complex(repr(1+6j)))
380 self.assertEqual(-6j,complex(repr(-6j)))
381 self.assertEqual(6j,complex(repr(6j)))
383 self.assertEqual(repr(complex(1., INF)), "(1+infj)")
384 self.assertEqual(repr(complex(1., -INF)), "(1-infj)")
385 self.assertEqual(repr(complex(INF, 1)), "(inf+1j)")
386 self.assertEqual(repr(complex(-INF, INF)), "(-inf+infj)")
387 self.assertEqual(repr(complex(NAN, 1)), "(nan+1j)")
388 self.assertEqual(repr(complex(1, NAN)), "(1+nanj)")
389 self.assertEqual(repr(complex(NAN, NAN)), "(nan+nanj)")
391 self.assertEqual(repr(complex(0, INF)), "infj")
392 self.assertEqual(repr(complex(0, -INF)), "-infj")
393 self.assertEqual(repr(complex(0, NAN)), "nanj")
395 def test_neg(self):
396 self.assertEqual(-(1+6j), -1-6j)
398 def test_file(self):
399 a = 3.33+4.43j
400 b = 5.1+2.3j
402 fo = None
403 try:
404 fo = open(test_support.TESTFN, "wb")
405 print >>fo, a, b
406 fo.close()
407 fo = open(test_support.TESTFN, "rb")
408 self.assertEqual(fo.read(), "%s %s\n" % (a, b))
409 finally:
410 if (fo is not None) and (not fo.closed):
411 fo.close()
412 try:
413 os.remove(test_support.TESTFN)
414 except (OSError, IOError):
415 pass
417 def test_getnewargs(self):
418 self.assertEqual((1+2j).__getnewargs__(), (1.0, 2.0))
419 self.assertEqual((1-2j).__getnewargs__(), (1.0, -2.0))
420 self.assertEqual((2j).__getnewargs__(), (0.0, 2.0))
421 self.assertEqual((-0j).__getnewargs__(), (0.0, -0.0))
422 self.assertEqual(complex(0, INF).__getnewargs__(), (0.0, INF))
423 self.assertEqual(complex(INF, 0).__getnewargs__(), (INF, 0.0))
425 if float.__getformat__("double").startswith("IEEE"):
426 def test_plus_minus_0j(self):
427 # test that -0j and 0j literals are not identified
428 z1, z2 = 0j, -0j
429 self.assertEquals(atan2(z1.imag, -1.), atan2(0., -1.))
430 self.assertEquals(atan2(z2.imag, -1.), atan2(-0., -1.))
432 @unittest.skipUnless(float.__getformat__("double").startswith("IEEE"),
433 "test requires IEEE 754 doubles")
434 def test_repr_roundtrip(self):
435 # complex(repr(z)) should recover z exactly, even for complex numbers
436 # involving an infinity, nan, or negative zero
437 vals = [0.0, 1e-200, 0.0123, 3.1415, 1e50, INF, NAN]
438 vals += [-v for v in vals]
439 for x in vals:
440 for y in vals:
441 z = complex(x, y)
442 roundtrip = complex(repr(z))
443 self.assertFloatsAreIdentical(z.real, roundtrip.real)
444 self.assertFloatsAreIdentical(z.imag, roundtrip.imag)
447 def test_main():
448 test_support.run_unittest(ComplexTest)
450 if __name__ == "__main__":
451 test_main()