diff options
author | Mark Dickinson <dickinsm@gmail.com> | 2009-12-11 20:17:17 (GMT) |
---|---|---|
committer | Mark Dickinson <dickinsm@gmail.com> | 2009-12-11 20:17:17 (GMT) |
commit | 05d2e084019d9ec67277df36acf372b81e18365f (patch) | |
tree | 7957bc8aabc2c09c7d9d39df92700f62ed474cf3 /Lib/test/test_math.py | |
parent | e62df2ffaa76a29ededa51380597bec54a1a1cc6 (diff) | |
download | cpython-05d2e084019d9ec67277df36acf372b81e18365f.zip cpython-05d2e084019d9ec67277df36acf372b81e18365f.tar.gz cpython-05d2e084019d9ec67277df36acf372b81e18365f.tar.bz2 |
Merged revisions 76755 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk
........
r76755 | mark.dickinson | 2009-12-11 17:29:33 +0000 (Fri, 11 Dec 2009) | 2 lines
Issue #3366: Add lgamma function to math module.
........
Diffstat (limited to 'Lib/test/test_math.py')
-rw-r--r-- | Lib/test/test_math.py | 50 |
1 files changed, 45 insertions, 5 deletions
diff --git a/Lib/test/test_math.py b/Lib/test/test_math.py index 2226023..2052430 100644 --- a/Lib/test/test_math.py +++ b/Lib/test/test_math.py @@ -48,6 +48,36 @@ def to_ulps(x): n = ~(n+2**63) return n +def ulps_check(expected, got, ulps=20): + """Given non-NaN floats `expected` and `got`, + check that they're equal to within the given number of ulps. + + Returns None on success and an error message on failure.""" + + ulps_error = to_ulps(got) - to_ulps(expected) + if abs(ulps_error) <= ulps: + return None + return "error = {} ulps; permitted error = {} ulps".format(ulps_error, + ulps) + +def acc_check(expected, got, rel_err=2e-15, abs_err = 5e-323): + """Determine whether non-NaN floats a and b are equal to within a + (small) rounding error. The default values for rel_err and + abs_err are chosen to be suitable for platforms where a float is + represented by an IEEE 754 double. They allow an error of between + 9 and 19 ulps.""" + + # need to special case infinities, since inf - inf gives nan + if math.isinf(expected) and got == expected: + return None + + error = got - expected + + permitted_error = max(abs_err, rel_err * abs(expected)) + if abs(error) < permitted_error: + return None + return "error = {}; permitted error = {}".format(error, + permitted_error) def parse_mtestfile(fname): """Parse a file with test values @@ -949,13 +979,23 @@ class MathTests(unittest.TestCase): except OverflowError: got = 'OverflowError' - diff_ulps = None + accuracy_failure = None if isinstance(got, float) and isinstance(expected, float): if math.isnan(expected) and math.isnan(got): continue if not math.isnan(expected) and not math.isnan(got): - diff_ulps = to_ulps(expected) - to_ulps(got) - if abs(diff_ulps) <= ALLOWED_ERROR: + # we use different closeness criteria for + # different functions. + if fn == 'gamma': + accuracy_failure = ulps_check(expected, got, 20) + elif fn == 'lgamma': + accuracy_failure = acc_check(expected, got, + rel_err = 5e-15, + abs_err = 5e-15) + else: + raise ValueError("don't know how to check accuracy " + "for this function") + if accuracy_failure is None: continue if isinstance(got, str) and isinstance(expected, str): @@ -963,8 +1003,8 @@ class MathTests(unittest.TestCase): continue fail_msg = fail_fmt.format(id, fn, arg, expected, got) - if diff_ulps is not None: - fail_msg += ' ({} ulps)'.format(diff_ulps) + if accuracy_failure is not None: + fail_msg += ' ({})'.format(accuracy_failure) failures.append(fail_msg) if failures: |