~malept/ubuntu/lucid/python2.6/dev-dependency-fix

« back to all changes in this revision

Viewing changes to Lib/test/test_cmath.py

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Klose
  • Date: 2009-02-13 12:51:00 UTC
  • Revision ID: james.westby@ubuntu.com-20090213125100-uufgcb9yeqzujpqw
Tags: upstream-2.6.1
ImportĀ upstreamĀ versionĀ 2.6.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
from test.test_support import run_unittest
 
2
from test.test_math import parse_testfile, test_file
 
3
import unittest
 
4
import os, sys
 
5
import cmath, math
 
6
from cmath import phase, polar, rect, pi
 
7
 
 
8
INF = float('inf')
 
9
NAN = float('nan')
 
10
 
 
11
complex_zeros = [complex(x, y) for x in [0.0, -0.0] for y in [0.0, -0.0]]
 
12
complex_infinities = [complex(x, y) for x, y in [
 
13
        (INF, 0.0),  # 1st quadrant
 
14
        (INF, 2.3),
 
15
        (INF, INF),
 
16
        (2.3, INF),
 
17
        (0.0, INF),
 
18
        (-0.0, INF), # 2nd quadrant
 
19
        (-2.3, INF),
 
20
        (-INF, INF),
 
21
        (-INF, 2.3),
 
22
        (-INF, 0.0),
 
23
        (-INF, -0.0), # 3rd quadrant
 
24
        (-INF, -2.3),
 
25
        (-INF, -INF),
 
26
        (-2.3, -INF),
 
27
        (-0.0, -INF),
 
28
        (0.0, -INF), # 4th quadrant
 
29
        (2.3, -INF),
 
30
        (INF, -INF),
 
31
        (INF, -2.3),
 
32
        (INF, -0.0)
 
33
        ]]
 
34
complex_nans = [complex(x, y) for x, y in [
 
35
        (NAN, -INF),
 
36
        (NAN, -2.3),
 
37
        (NAN, -0.0),
 
38
        (NAN, 0.0),
 
39
        (NAN, 2.3),
 
40
        (NAN, INF),
 
41
        (-INF, NAN),
 
42
        (-2.3, NAN),
 
43
        (-0.0, NAN),
 
44
        (0.0, NAN),
 
45
        (2.3, NAN),
 
46
        (INF, NAN)
 
47
        ]]
 
48
 
 
49
def almostEqualF(a, b, rel_err=2e-15, abs_err = 5e-323):
 
50
    """Determine whether floating-point values a and b are equal to within
 
51
    a (small) rounding error.  The default values for rel_err and
 
52
    abs_err are chosen to be suitable for platforms where a float is
 
53
    represented by an IEEE 754 double.  They allow an error of between
 
54
    9 and 19 ulps."""
 
55
 
 
56
    # special values testing
 
57
    if math.isnan(a):
 
58
        return math.isnan(b)
 
59
    if math.isinf(a):
 
60
        return a == b
 
61
 
 
62
    # if both a and b are zero, check whether they have the same sign
 
63
    # (in theory there are examples where it would be legitimate for a
 
64
    # and b to have opposite signs; in practice these hardly ever
 
65
    # occur).
 
66
    if not a and not b:
 
67
        return math.copysign(1., a) == math.copysign(1., b)
 
68
 
 
69
    # if a-b overflows, or b is infinite, return False.  Again, in
 
70
    # theory there are examples where a is within a few ulps of the
 
71
    # max representable float, and then b could legitimately be
 
72
    # infinite.  In practice these examples are rare.
 
73
    try:
 
74
        absolute_error = abs(b-a)
 
75
    except OverflowError:
 
76
        return False
 
77
    else:
 
78
        return absolute_error <= max(abs_err, rel_err * abs(a))
 
79
 
 
80
class CMathTests(unittest.TestCase):
 
81
    # list of all functions in cmath
 
82
    test_functions = [getattr(cmath, fname) for fname in [
 
83
            'acos', 'acosh', 'asin', 'asinh', 'atan', 'atanh',
 
84
            'cos', 'cosh', 'exp', 'log', 'log10', 'sin', 'sinh',
 
85
            'sqrt', 'tan', 'tanh']]
 
86
    # test first and second arguments independently for 2-argument log
 
87
    test_functions.append(lambda x : cmath.log(x, 1729. + 0j))
 
88
    test_functions.append(lambda x : cmath.log(14.-27j, x))
 
89
 
 
90
    def setUp(self):
 
91
        self.test_values = open(test_file)
 
92
 
 
93
    def tearDown(self):
 
94
        self.test_values.close()
 
95
 
 
96
    def rAssertAlmostEqual(self, a, b, rel_err = 2e-15, abs_err = 5e-323):
 
97
        """Check that two floating-point numbers are almost equal."""
 
98
 
 
99
        # special values testing
 
100
        if math.isnan(a):
 
101
            if math.isnan(b):
 
102
                return
 
103
            self.fail("%s should be nan" % repr(b))
 
104
 
 
105
        if math.isinf(a):
 
106
            if a == b:
 
107
                return
 
108
            self.fail("finite result where infinity excpected: "
 
109
                      "expected %s, got %s" % (repr(a), repr(b)))
 
110
 
 
111
        if not a and not b:
 
112
            if math.atan2(a, -1.) != math.atan2(b, -1.):
 
113
                self.fail("zero has wrong sign: expected %s, got %s" %
 
114
                          (repr(a), repr(b)))
 
115
 
 
116
        # test passes if either the absolute error or the relative
 
117
        # error is sufficiently small.  The defaults amount to an
 
118
        # error of between 9 ulps and 19 ulps on an IEEE-754 compliant
 
119
        # machine.
 
120
 
 
121
        try:
 
122
            absolute_error = abs(b-a)
 
123
        except OverflowError:
 
124
            pass
 
125
        else:
 
126
            if absolute_error <= max(abs_err, rel_err * abs(a)):
 
127
                return
 
128
        self.fail("%s and %s are not sufficiently close" % (repr(a), repr(b)))
 
129
 
 
130
    def test_constants(self):
 
131
        e_expected = 2.71828182845904523536
 
132
        pi_expected = 3.14159265358979323846
 
133
        self.rAssertAlmostEqual(cmath.pi, pi_expected, 9,
 
134
            "cmath.pi is %s; should be %s" % (cmath.pi, pi_expected))
 
135
        self.rAssertAlmostEqual(cmath.e,  e_expected, 9,
 
136
            "cmath.e is %s; should be %s" % (cmath.e, e_expected))
 
137
 
 
138
    def test_user_object(self):
 
139
        # Test automatic calling of __complex__ and __float__ by cmath
 
140
        # functions
 
141
 
 
142
        # some random values to use as test values; we avoid values
 
143
        # for which any of the functions in cmath is undefined
 
144
        # (i.e. 0., 1., -1., 1j, -1j) or would cause overflow
 
145
        cx_arg = 4.419414439 + 1.497100113j
 
146
        flt_arg = -6.131677725
 
147
 
 
148
        # a variety of non-complex numbers, used to check that
 
149
        # non-complex return values from __complex__ give an error
 
150
        non_complexes = ["not complex", 1, 5L, 2., None,
 
151
                         object(), NotImplemented]
 
152
 
 
153
        # Now we introduce a variety of classes whose instances might
 
154
        # end up being passed to the cmath functions
 
155
 
 
156
        # usual case: new-style class implementing __complex__
 
157
        class MyComplex(object):
 
158
            def __init__(self, value):
 
159
                self.value = value
 
160
            def __complex__(self):
 
161
                return self.value
 
162
 
 
163
        # old-style class implementing __complex__
 
164
        class MyComplexOS:
 
165
            def __init__(self, value):
 
166
                self.value = value
 
167
            def __complex__(self):
 
168
                return self.value
 
169
 
 
170
        # classes for which __complex__ raises an exception
 
171
        class SomeException(Exception):
 
172
            pass
 
173
        class MyComplexException(object):
 
174
            def __complex__(self):
 
175
                raise SomeException
 
176
        class MyComplexExceptionOS:
 
177
            def __complex__(self):
 
178
                raise SomeException
 
179
 
 
180
        # some classes not providing __float__ or __complex__
 
181
        class NeitherComplexNorFloat(object):
 
182
            pass
 
183
        class NeitherComplexNorFloatOS:
 
184
            pass
 
185
        class MyInt(object):
 
186
            def __int__(self): return 2
 
187
            def __long__(self): return 2L
 
188
            def __index__(self): return 2
 
189
        class MyIntOS:
 
190
            def __int__(self): return 2
 
191
            def __long__(self): return 2L
 
192
            def __index__(self): return 2
 
193
 
 
194
        # other possible combinations of __float__ and __complex__
 
195
        # that should work
 
196
        class FloatAndComplex(object):
 
197
            def __float__(self):
 
198
                return flt_arg
 
199
            def __complex__(self):
 
200
                return cx_arg
 
201
        class FloatAndComplexOS:
 
202
            def __float__(self):
 
203
                return flt_arg
 
204
            def __complex__(self):
 
205
                return cx_arg
 
206
        class JustFloat(object):
 
207
            def __float__(self):
 
208
                return flt_arg
 
209
        class JustFloatOS:
 
210
            def __float__(self):
 
211
                return flt_arg
 
212
 
 
213
        for f in self.test_functions:
 
214
            # usual usage
 
215
            self.assertEqual(f(MyComplex(cx_arg)), f(cx_arg))
 
216
            self.assertEqual(f(MyComplexOS(cx_arg)), f(cx_arg))
 
217
            # other combinations of __float__ and __complex__
 
218
            self.assertEqual(f(FloatAndComplex()), f(cx_arg))
 
219
            self.assertEqual(f(FloatAndComplexOS()), f(cx_arg))
 
220
            self.assertEqual(f(JustFloat()), f(flt_arg))
 
221
            self.assertEqual(f(JustFloatOS()), f(flt_arg))
 
222
            # TypeError should be raised for classes not providing
 
223
            # either __complex__ or __float__, even if they provide
 
224
            # __int__, __long__ or __index__.  An old-style class
 
225
            # currently raises AttributeError instead of a TypeError;
 
226
            # this could be considered a bug.
 
227
            self.assertRaises(TypeError, f, NeitherComplexNorFloat())
 
228
            self.assertRaises(TypeError, f, MyInt())
 
229
            self.assertRaises(Exception, f, NeitherComplexNorFloatOS())
 
230
            self.assertRaises(Exception, f, MyIntOS())
 
231
            # non-complex return value from __complex__ -> TypeError
 
232
            for bad_complex in non_complexes:
 
233
                self.assertRaises(TypeError, f, MyComplex(bad_complex))
 
234
                self.assertRaises(TypeError, f, MyComplexOS(bad_complex))
 
235
            # exceptions in __complex__ should be propagated correctly
 
236
            self.assertRaises(SomeException, f, MyComplexException())
 
237
            self.assertRaises(SomeException, f, MyComplexExceptionOS())
 
238
 
 
239
    def test_input_type(self):
 
240
        # ints and longs should be acceptable inputs to all cmath
 
241
        # functions, by virtue of providing a __float__ method
 
242
        for f in self.test_functions:
 
243
            for arg in [2, 2L, 2.]:
 
244
                self.assertEqual(f(arg), f(arg.__float__()))
 
245
 
 
246
        # but strings should give a TypeError
 
247
        for f in self.test_functions:
 
248
            for arg in ["a", "long_string", "0", "1j", ""]:
 
249
                self.assertRaises(TypeError, f, arg)
 
250
 
 
251
    def test_cmath_matches_math(self):
 
252
        # check that corresponding cmath and math functions are equal
 
253
        # for floats in the appropriate range
 
254
 
 
255
        # test_values in (0, 1)
 
256
        test_values = [0.01, 0.1, 0.2, 0.5, 0.9, 0.99]
 
257
 
 
258
        # test_values for functions defined on [-1., 1.]
 
259
        unit_interval = test_values + [-x for x in test_values] + \
 
260
            [0., 1., -1.]
 
261
 
 
262
        # test_values for log, log10, sqrt
 
263
        positive = test_values + [1.] + [1./x for x in test_values]
 
264
        nonnegative = [0.] + positive
 
265
 
 
266
        # test_values for functions defined on the whole real line
 
267
        real_line = [0.] + positive + [-x for x in positive]
 
268
 
 
269
        test_functions = {
 
270
            'acos' : unit_interval,
 
271
            'asin' : unit_interval,
 
272
            'atan' : real_line,
 
273
            'cos' : real_line,
 
274
            'cosh' : real_line,
 
275
            'exp' : real_line,
 
276
            'log' : positive,
 
277
            'log10' : positive,
 
278
            'sin' : real_line,
 
279
            'sinh' : real_line,
 
280
            'sqrt' : nonnegative,
 
281
            'tan' : real_line,
 
282
            'tanh' : real_line}
 
283
 
 
284
        for fn, values in test_functions.items():
 
285
            float_fn = getattr(math, fn)
 
286
            complex_fn = getattr(cmath, fn)
 
287
            for v in values:
 
288
                z = complex_fn(v)
 
289
                self.rAssertAlmostEqual(float_fn(v), z.real)
 
290
                self.assertEqual(0., z.imag)
 
291
 
 
292
        # test two-argument version of log with various bases
 
293
        for base in [0.5, 2., 10.]:
 
294
            for v in positive:
 
295
                z = cmath.log(v, base)
 
296
                self.rAssertAlmostEqual(math.log(v, base), z.real)
 
297
                self.assertEqual(0., z.imag)
 
298
 
 
299
    def test_specific_values(self):
 
300
        if not float.__getformat__("double").startswith("IEEE"):
 
301
            return
 
302
 
 
303
        def rect_complex(z):
 
304
            """Wrapped version of rect that accepts a complex number instead of
 
305
            two float arguments."""
 
306
            return cmath.rect(z.real, z.imag)
 
307
 
 
308
        def polar_complex(z):
 
309
            """Wrapped version of polar that returns a complex number instead of
 
310
            two floats."""
 
311
            return complex(*polar(z))
 
312
 
 
313
        for id, fn, ar, ai, er, ei, flags in parse_testfile(test_file):
 
314
            arg = complex(ar, ai)
 
315
            expected = complex(er, ei)
 
316
            if fn == 'rect':
 
317
                function = rect_complex
 
318
            elif fn == 'polar':
 
319
                function = polar_complex
 
320
            else:
 
321
                function = getattr(cmath, fn)
 
322
            if 'divide-by-zero' in flags or 'invalid' in flags:
 
323
                try:
 
324
                    actual = function(arg)
 
325
                except ValueError:
 
326
                    continue
 
327
                else:
 
328
                    test_str = "%s: %s(complex(%r, %r))" % (id, fn, ar, ai)
 
329
                    self.fail('ValueError not raised in test %s' % test_str)
 
330
 
 
331
            if 'overflow' in flags:
 
332
                try:
 
333
                    actual = function(arg)
 
334
                except OverflowError:
 
335
                    continue
 
336
                else:
 
337
                    test_str = "%s: %s(complex(%r, %r))" % (id, fn, ar, ai)
 
338
                    self.fail('OverflowError not raised in test %s' % test_str)
 
339
 
 
340
            actual = function(arg)
 
341
 
 
342
            if 'ignore-real-sign' in flags:
 
343
                actual = complex(abs(actual.real), actual.imag)
 
344
                expected = complex(abs(expected.real), expected.imag)
 
345
            if 'ignore-imag-sign' in flags:
 
346
                actual = complex(actual.real, abs(actual.imag))
 
347
                expected = complex(expected.real, abs(expected.imag))
 
348
 
 
349
            # for the real part of the log function, we allow an
 
350
            # absolute error of up to 2e-15.
 
351
            if fn in ('log', 'log10'):
 
352
                real_abs_err = 2e-15
 
353
            else:
 
354
                real_abs_err = 5e-323
 
355
 
 
356
            if not (almostEqualF(expected.real, actual.real,
 
357
                                 abs_err = real_abs_err) and
 
358
                    almostEqualF(expected.imag, actual.imag)):
 
359
                error_message = (
 
360
                    "%s: %s(complex(%r, %r))\n" % (id, fn, ar, ai) +
 
361
                    "Expected: complex(%r, %r)\n" %
 
362
                                    (expected.real, expected.imag) +
 
363
                    "Received: complex(%r, %r)\n" %
 
364
                                    (actual.real, actual.imag) +
 
365
                    "Received value insufficiently close to expected value.")
 
366
                self.fail(error_message)
 
367
 
 
368
    def assertCISEqual(self, a, b):
 
369
        eps = 1E-7
 
370
        if abs(a[0] - b[0]) > eps or abs(a[1] - b[1]) > eps:
 
371
            self.fail((a ,b))
 
372
 
 
373
    def test_polar(self):
 
374
        self.assertCISEqual(polar(0), (0., 0.))
 
375
        self.assertCISEqual(polar(1.), (1., 0.))
 
376
        self.assertCISEqual(polar(-1.), (1., pi))
 
377
        self.assertCISEqual(polar(1j), (1., pi/2))
 
378
        self.assertCISEqual(polar(-1j), (1., -pi/2))
 
379
 
 
380
    def test_phase(self):
 
381
        self.assertAlmostEqual(phase(0), 0.)
 
382
        self.assertAlmostEqual(phase(1.), 0.)
 
383
        self.assertAlmostEqual(phase(-1.), pi)
 
384
        self.assertAlmostEqual(phase(-1.+1E-300j), pi)
 
385
        self.assertAlmostEqual(phase(-1.-1E-300j), -pi)
 
386
        self.assertAlmostEqual(phase(1j), pi/2)
 
387
        self.assertAlmostEqual(phase(-1j), -pi/2)
 
388
 
 
389
        # zeros
 
390
        self.assertEqual(phase(complex(0.0, 0.0)), 0.0)
 
391
        self.assertEqual(phase(complex(0.0, -0.0)), -0.0)
 
392
        self.assertEqual(phase(complex(-0.0, 0.0)), pi)
 
393
        self.assertEqual(phase(complex(-0.0, -0.0)), -pi)
 
394
 
 
395
        # infinities
 
396
        self.assertAlmostEqual(phase(complex(-INF, -0.0)), -pi)
 
397
        self.assertAlmostEqual(phase(complex(-INF, -2.3)), -pi)
 
398
        self.assertAlmostEqual(phase(complex(-INF, -INF)), -0.75*pi)
 
399
        self.assertAlmostEqual(phase(complex(-2.3, -INF)), -pi/2)
 
400
        self.assertAlmostEqual(phase(complex(-0.0, -INF)), -pi/2)
 
401
        self.assertAlmostEqual(phase(complex(0.0, -INF)), -pi/2)
 
402
        self.assertAlmostEqual(phase(complex(2.3, -INF)), -pi/2)
 
403
        self.assertAlmostEqual(phase(complex(INF, -INF)), -pi/4)
 
404
        self.assertEqual(phase(complex(INF, -2.3)), -0.0)
 
405
        self.assertEqual(phase(complex(INF, -0.0)), -0.0)
 
406
        self.assertEqual(phase(complex(INF, 0.0)), 0.0)
 
407
        self.assertEqual(phase(complex(INF, 2.3)), 0.0)
 
408
        self.assertAlmostEqual(phase(complex(INF, INF)), pi/4)
 
409
        self.assertAlmostEqual(phase(complex(2.3, INF)), pi/2)
 
410
        self.assertAlmostEqual(phase(complex(0.0, INF)), pi/2)
 
411
        self.assertAlmostEqual(phase(complex(-0.0, INF)), pi/2)
 
412
        self.assertAlmostEqual(phase(complex(-2.3, INF)), pi/2)
 
413
        self.assertAlmostEqual(phase(complex(-INF, INF)), 0.75*pi)
 
414
        self.assertAlmostEqual(phase(complex(-INF, 2.3)), pi)
 
415
        self.assertAlmostEqual(phase(complex(-INF, 0.0)), pi)
 
416
 
 
417
        # real or imaginary part NaN
 
418
        for z in complex_nans:
 
419
            self.assert_(math.isnan(phase(z)))
 
420
 
 
421
    def test_abs(self):
 
422
        # zeros
 
423
        for z in complex_zeros:
 
424
            self.assertEqual(abs(z), 0.0)
 
425
 
 
426
        # infinities
 
427
        for z in complex_infinities:
 
428
            self.assertEqual(abs(z), INF)
 
429
 
 
430
        # real or imaginary part NaN
 
431
        self.assertEqual(abs(complex(NAN, -INF)), INF)
 
432
        self.assert_(math.isnan(abs(complex(NAN, -2.3))))
 
433
        self.assert_(math.isnan(abs(complex(NAN, -0.0))))
 
434
        self.assert_(math.isnan(abs(complex(NAN, 0.0))))
 
435
        self.assert_(math.isnan(abs(complex(NAN, 2.3))))
 
436
        self.assertEqual(abs(complex(NAN, INF)), INF)
 
437
        self.assertEqual(abs(complex(-INF, NAN)), INF)
 
438
        self.assert_(math.isnan(abs(complex(-2.3, NAN))))
 
439
        self.assert_(math.isnan(abs(complex(-0.0, NAN))))
 
440
        self.assert_(math.isnan(abs(complex(0.0, NAN))))
 
441
        self.assert_(math.isnan(abs(complex(2.3, NAN))))
 
442
        self.assertEqual(abs(complex(INF, NAN)), INF)
 
443
        self.assert_(math.isnan(abs(complex(NAN, NAN))))
 
444
 
 
445
        # result overflows
 
446
        if float.__getformat__("double").startswith("IEEE"):
 
447
            self.assertRaises(OverflowError, abs, complex(1.4e308, 1.4e308))
 
448
 
 
449
    def assertCEqual(self, a, b):
 
450
        eps = 1E-7
 
451
        if abs(a.real - b[0]) > eps or abs(a.imag - b[1]) > eps:
 
452
            self.fail((a ,b))
 
453
 
 
454
    def test_rect(self):
 
455
        self.assertCEqual(rect(0, 0), (0, 0))
 
456
        self.assertCEqual(rect(1, 0), (1., 0))
 
457
        self.assertCEqual(rect(1, -pi), (-1., 0))
 
458
        self.assertCEqual(rect(1, pi/2), (0, 1.))
 
459
        self.assertCEqual(rect(1, -pi/2), (0, -1.))
 
460
 
 
461
    def test_isnan(self):
 
462
        self.failIf(cmath.isnan(1))
 
463
        self.failIf(cmath.isnan(1j))
 
464
        self.failIf(cmath.isnan(INF))
 
465
        self.assert_(cmath.isnan(NAN))
 
466
        self.assert_(cmath.isnan(complex(NAN, 0)))
 
467
        self.assert_(cmath.isnan(complex(0, NAN)))
 
468
        self.assert_(cmath.isnan(complex(NAN, NAN)))
 
469
        self.assert_(cmath.isnan(complex(NAN, INF)))
 
470
        self.assert_(cmath.isnan(complex(INF, NAN)))
 
471
 
 
472
    def test_isinf(self):
 
473
        self.failIf(cmath.isinf(1))
 
474
        self.failIf(cmath.isinf(1j))
 
475
        self.failIf(cmath.isinf(NAN))
 
476
        self.assert_(cmath.isinf(INF))
 
477
        self.assert_(cmath.isinf(complex(INF, 0)))
 
478
        self.assert_(cmath.isinf(complex(0, INF)))
 
479
        self.assert_(cmath.isinf(complex(INF, INF)))
 
480
        self.assert_(cmath.isinf(complex(NAN, INF)))
 
481
        self.assert_(cmath.isinf(complex(INF, NAN)))
 
482
 
 
483
 
 
484
def test_main():
 
485
    run_unittest(CMathTests)
 
486
 
 
487
if __name__ == "__main__":
 
488
    test_main()