-
Notifications
You must be signed in to change notification settings - Fork 4
/
test_isclose_c.py
241 lines (182 loc) · 7.18 KB
/
test_isclose_c.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
#!/usr/bin/env python3
"""
Unit tests for isclose function -- this one tests the c
version in is_close_module.py
"""
import unittest
from is_close_module import isclose
from decimal import Decimal
from fractions import Fraction
class ErrorTestCase(unittest.TestCase):
"""
ValueError should be raised if either tolerance is set to less than zero
But maybe not bother?
"""
def test_negative_tol(self):
with self.assertRaises(ValueError):
isclose(1, 1, -1e-100)
def test_negative_abstol(self):
with self.assertRaises(ValueError):
isclose(1, 1, 1e-100, -1e10)
class CloseTestCase(unittest.TestCase):
""" some methods that make it easier to get a nice error message,
and/or test a bunch of values
"""
def do_close(self, a, b, *args, **kwargs):
self.assertTrue(isclose(a, b, *args, **kwargs),
msg="%s and %s should be close!" % (a, b))
def do_not_close(self, a, b, *args, **kwargs):
self.assertFalse(isclose(a, b, *args, **kwargs),
msg="%s and %s should not be close!" % (a, b))
def do_close_all(self, examples, *args, **kwargs):
for a, b in examples:
self.assertTrue(isclose(a, b, *args, **kwargs),
msg=("%s and %s should be close" % (a, b))
)
def do_not_close_all(self, examples, *args, **kwargs):
for a, b in examples:
self.assertFalse(isclose(a, b, *args, **kwargs),
msg=("%s and %s should not be close" % (a, b))
)
class ExactTestCase(CloseTestCase):
"""
Make sure exact values test as close
"""
exact_examples = [(2.0, 2.0),
(0.1e200, 0.1e200),
(1.123e-300, 1.123e-300),
(12345, 12345.0),
(0.0, -0.0),
(345678, 345678)
]
def test_exact(self):
# should return close even with zero tolerances
self.do_close_all(self.exact_examples,
rel_tol=0.0,
abs_tol=0.0)
class RelativeTestCase(CloseTestCase):
# examples that are close to 1e-8, but not 1e-9
nums8 = [(1e8, 1e8 + 1),
(-1e-8, -1.000000009e-8),
(1.12345678, 1.12345679),
]
def test_all_8close(self):
self.do_close_all(self.nums8, rel_tol=1e-8)
def test_all_8_not_close(self):
self.do_not_close_all(self.nums8, rel_tol=1e-9)
class ZeroTestCase(CloseTestCase):
# values close to zero
nums0 = [(1e-9, 0.0),
(-1e-9, 0.0),
(-1e-150, 0.0),
]
def test_nums8_not_close(self):
# these should not be close to any rel_tol
self.do_not_close_all(self.nums0, rel_tol=0.9)
def test_nums8_close(self):
# these should be close to abs_tol=1e-8
self.do_close_all(self.nums0, abs_tol=1e-8)
class NonFiniteCase(CloseTestCase):
""" tests for nan, inf, -inf """
inf = float('inf')
nan = float('nan')
# these are close regardless of tolerance -- i.e. they are equal
close_examples = [(inf, inf),
(-inf, -inf),
]
# these should never be close (following IEEE 754 rules for equality)
not_close_examples = [(nan, nan),
(nan, 1e-100),
(1e-100, nan),
(inf, nan),
(nan, inf),
(inf, -inf),
(inf, 1.0),
(1.0, inf),
(inf, 1e308),
(1e308, inf),
]
def test_close(self):
# zero tolerance -- only equal will be close
self.do_close_all(self.close_examples, abs_tol=0.0)
def test_not_close(self):
# largest tolerance possible (or at least reasonable)
self.do_not_close_all(self.not_close_examples,
abs_tol=0.999999999999999)
class ZeroTolTest(CloseTestCase):
"""
zero tolerance should not be close for anything except exactly equal
quantities
"""
# these are close regardless of tolerance -- i.e. they are equal
close_examples = [(1.0, 1.0),
(-3.4, -3.4),
(-1e-300, -1e-300)
]
# these should never be close
not_close_examples = [(1.0, 1.000000000000001),
(0.99999999999999, 1.0),
(1.0e200, .999999999999999e200),
]
def test_close(self):
# zero tolerance -- only equal will be close
self.do_close_all(self.close_examples, rel_tol=0.0)
def test_not_close(self):
# largest tolerance possible (or at least reasonable)
self.do_not_close_all(self.not_close_examples,
rel_tol=0.0)
class AsymetryTest(CloseTestCase):
"""
tests the assymetry example from the PEP
"""
# should pass weak test both orders
def test_close_weak(self):
self.do_close(9, 10, rel_tol=0.1)
def test_close_weak_reversed(self):
self.do_close(10, 9, rel_tol=0.1)
# class ComplexTests(CloseTestCase):
# close_examples = [(1.0+1.0j, 1.000000000001+1.0j),
# (1.0+1.0j, 1.0+1.000000000001j),
# (-1.0+1.0j, -1.000000000001+1.0j),
# (1.0-1.0j, 1.0-0.999999999999j),
# ]
# def test_close(self):
# self.do_close_all(self.close_examples, rel_tol=1e-12)
# # for a,b in self.close_examples:
# # self.do_close(a, b, rel_tol=1e-12)
# def test_not_close(self):
# self.do_not_close_all(self.close_examples, rel_tol=1e-13)
# # for a,b in self.close_examples:
# # self.do_not_close(a, b, rel_tol=1e-14)
class TestInteger(CloseTestCase):
close_examples = [(100000001, 100000000),
(123456789, 123456788)
]
def test_close(self):
self.do_close_all(self.close_examples, rel_tol=1e-8)
def test_not_close(self):
self.do_not_close_all(self.close_examples, rel_tol=1e-9)
class TestDecimal(CloseTestCase):
"""
test some Decimal values
note that these are converted to floats inside teh function
"""
close_examples = [(Decimal('1.00000001'), Decimal('1.0')),
(Decimal('1.00000001e-20'), Decimal('1.0e-20')),
(Decimal('1.00000001e-100'), Decimal('1.0e-100')),
]
def test_close(self):
self.do_close_all(self.close_examples, rel_tol=1e-8)
def test_not_close(self):
self.do_not_close_all(self.close_examples, rel_tol=1e-9)
class TestFraction(CloseTestCase):
# could use some more here!
"""
note that these are converted to floats internally
"""
close_examples = [(Fraction(1, 100000000) + 1, Fraction(1)),
]
def test_close(self):
self.do_close_all(self.close_examples, rel_tol=1e-8)
def test_not_close(self):
self.do_not_close_all(self.close_examples, rel_tol=1e-9)