|
5 | 5 | import math
|
6 | 6 | import unittest
|
7 | 7 | import sys
|
| 8 | +import struct |
8 | 9 |
|
9 | 10 | eps = 1E-05
|
10 | 11 | INF = float('inf')
|
@@ -44,6 +45,40 @@ def py_factorial(n):
|
44 | 45 | outer *= inner
|
45 | 46 | return outer << (n - count_set_bits(n))
|
46 | 47 |
|
| 48 | +def to_ulps(x): |
| 49 | + """Convert a non-NaN float x to an integer, in such a way that |
| 50 | + adjacent floats are converted to adjacent integers. Then |
| 51 | + abs(ulps(x) - ulps(y)) gives the difference in ulps between two |
| 52 | + floats. |
| 53 | +
|
| 54 | + The results from this function will only make sense on platforms |
| 55 | + where native doubles are represented in IEEE 754 binary64 format. |
| 56 | +
|
| 57 | + Note: 0.0 and -0.0 are converted to 0 and -1, respectively. |
| 58 | + """ |
| 59 | + n = struct.unpack('<q', struct.pack('<d', x))[0] |
| 60 | + if n < 0: |
| 61 | + n = ~(n+2**63) |
| 62 | + return n |
| 63 | + |
| 64 | +def ulp_abs_check(expected, got, ulp_tol, abs_tol): |
| 65 | + """Given finite floats `expected` and `got`, check that they're |
| 66 | + approximately equal to within the given number of ulps or the |
| 67 | + given absolute tolerance, whichever is bigger. |
| 68 | +
|
| 69 | + Returns None on success and an error message on failure. |
| 70 | + """ |
| 71 | + ulp_error = abs(to_ulps(expected) - to_ulps(got)) |
| 72 | + abs_error = abs(expected - got) |
| 73 | + |
| 74 | + # Succeed if either abs_error <= abs_tol or ulp_error <= ulp_tol. |
| 75 | + if abs_error <= abs_tol or ulp_error <= ulp_tol: |
| 76 | + return None |
| 77 | + else: |
| 78 | + fmt = ("error = {:.3g} ({:d} ulps); " |
| 79 | + "permitted error = {:.3g} or {:d} ulps") |
| 80 | + return fmt.format(abs_error, ulp_error, abs_tol, ulp_tol) |
| 81 | + |
47 | 82 | def result_check(expected, got, ulp_tol=5, abs_tol=0.0):
|
48 | 83 | # Common logic of MathTests.(ftest, test_testcases, test_mtestcases)
|
49 | 84 | """Compare arguments expected and got, as floats, if either
|
@@ -140,6 +175,24 @@ def __float__(self):
|
140 | 175 | return 'ahoj'
|
141 | 176 | self.assertRaises(TypeError, math.acos, MyFloat3())
|
142 | 177 |
|
| 178 | + def testAcosh(self): |
| 179 | + self.assertRaises(TypeError, math.acosh) |
| 180 | + self.ftest('acosh(1)', math.acosh(1), 0) |
| 181 | + # TODO uncomment when GR-10346 will be fixed |
| 182 | + #self.ftest('acosh(2)', math.acosh(2), 1.3169578969248168) |
| 183 | + self.assertRaises(ValueError, math.acosh, 0) |
| 184 | + self.assertRaises(ValueError, math.acosh, -1) |
| 185 | + self.assertEqual(math.acosh(INF), INF) |
| 186 | + self.assertRaises(ValueError, math.acosh, NINF) |
| 187 | + self.assertTrue(math.isnan(math.acosh(NAN))) |
| 188 | + |
| 189 | + class MyFF: |
| 190 | + def __float__(self): |
| 191 | + return 6 |
| 192 | + # TODO uncomment when GR-10346 will be fixed |
| 193 | + #self.ftest('acos(MyFloat())', math.acosh(MyFF()), 0.9272952180016123) |
| 194 | + self.assertRaises(ValueError, math.acosh, MyFloat()) |
| 195 | + |
143 | 196 | def testIsfinite(self):
|
144 | 197 | self.assertTrue(math.isfinite(0.0))
|
145 | 198 | self.assertTrue(math.isfinite(-0.0))
|
|
0 commit comments