Skip to content

Commit 486be25

Browse files
authored
ENH: Allow relative and/or absolute precision in assert_almost_equal (#30562)
1 parent cdea41e commit 486be25

15 files changed

+354
-139
lines changed

doc/source/whatsnew/v1.1.0.rst

+3
Original file line numberDiff line numberDiff line change
@@ -802,6 +802,9 @@ Deprecations
802802
- The ``squeeze`` keyword in the ``groupby`` function is deprecated and will be removed in a future version (:issue:`32380`)
803803
- The ``tz`` keyword in :meth:`Period.to_timestamp` is deprecated and will be removed in a future version; use `per.to_timestamp(...).tz_localize(tz)`` instead (:issue:`34522`)
804804
- :meth:`DatetimeIndex.to_perioddelta` is deprecated and will be removed in a future version. Use ``index - index.to_period(freq).to_timestamp()`` instead (:issue:`34853`)
805+
- :meth:`util.testing.assert_almost_equal` now accepts both relative and absolute
806+
precision through the ``rtol``, and ``atol`` parameters, thus deprecating the
807+
``check_less_precise`` parameter. (:issue:`13357`).
805808

806809
.. ---------------------------------------------------------------------------
807810

pandas/_libs/testing.pyx

+20-38
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import math
2+
13
import numpy as np
24
from numpy cimport import_array
35
import_array()
@@ -42,12 +44,6 @@ cdef bint is_dictlike(obj):
4244
return hasattr(obj, 'keys') and hasattr(obj, '__getitem__')
4345

4446

45-
cdef bint decimal_almost_equal(double desired, double actual, int decimal):
46-
# Code from
47-
# https://numpy.org/doc/stable/reference/generated/numpy.testing.assert_almost_equal.html
48-
return abs(desired - actual) < (0.5 * 10.0 ** -decimal)
49-
50-
5147
cpdef assert_dict_equal(a, b, bint compare_keys=True):
5248
assert is_dictlike(a) and is_dictlike(b), (
5349
"Cannot compare dict objects, one or both is not dict-like"
@@ -66,7 +62,7 @@ cpdef assert_dict_equal(a, b, bint compare_keys=True):
6662

6763

6864
cpdef assert_almost_equal(a, b,
69-
check_less_precise=False,
65+
rtol=1.e-5, atol=1.e-8,
7066
bint check_dtype=True,
7167
obj=None, lobj=None, robj=None, index_values=None):
7268
"""
@@ -76,31 +72,33 @@ cpdef assert_almost_equal(a, b,
7672
----------
7773
a : object
7874
b : object
79-
check_less_precise : bool or int, default False
80-
Specify comparison precision.
81-
5 digits (False) or 3 digits (True) after decimal points are
82-
compared. If an integer, then this will be the number of decimal
83-
points to compare
75+
rtol : float, default 1e-5
76+
Relative tolerance.
77+
78+
.. versionadded:: 1.1.0
79+
atol : float, default 1e-8
80+
Absolute tolerance.
81+
82+
.. versionadded:: 1.1.0
8483
check_dtype: bool, default True
85-
check dtype if both a and b are np.ndarray
84+
check dtype if both a and b are np.ndarray.
8685
obj : str, default None
8786
Specify object name being compared, internally used to show
88-
appropriate assertion message
87+
appropriate assertion message.
8988
lobj : str, default None
9089
Specify left object name being compared, internally used to show
91-
appropriate assertion message
90+
appropriate assertion message.
9291
robj : str, default None
9392
Specify right object name being compared, internally used to show
94-
appropriate assertion message
93+
appropriate assertion message.
9594
index_values : ndarray, default None
9695
Specify shared index values of objects being compared, internally used
97-
to show appropriate assertion message
96+
to show appropriate assertion message.
9897
9998
.. versionadded:: 1.1.0
10099
101100
"""
102101
cdef:
103-
int decimal
104102
double diff = 0.0
105103
Py_ssize_t i, na, nb
106104
double fa, fb
@@ -111,8 +109,6 @@ cpdef assert_almost_equal(a, b,
111109
if robj is None:
112110
robj = b
113111

114-
assert isinstance(check_less_precise, (int, bool))
115-
116112
if isinstance(a, dict) or isinstance(b, dict):
117113
return assert_dict_equal(a, b)
118114

@@ -170,8 +166,7 @@ cpdef assert_almost_equal(a, b,
170166

171167
for i in range(len(a)):
172168
try:
173-
assert_almost_equal(a[i], b[i],
174-
check_less_precise=check_less_precise)
169+
assert_almost_equal(a[i], b[i], rtol=rtol, atol=atol)
175170
except AssertionError:
176171
is_unequal = True
177172
diff += 1
@@ -203,24 +198,11 @@ cpdef assert_almost_equal(a, b,
203198
# inf comparison
204199
return True
205200

206-
if check_less_precise is True:
207-
decimal = 3
208-
elif check_less_precise is False:
209-
decimal = 5
210-
else:
211-
decimal = check_less_precise
212-
213201
fa, fb = a, b
214202

215-
# case for zero
216-
if abs(fa) < 1e-5:
217-
if not decimal_almost_equal(fa, fb, decimal):
218-
assert False, (f'(very low values) expected {fb:.5f} '
219-
f'but got {fa:.5f}, with decimal {decimal}')
220-
else:
221-
if not decimal_almost_equal(1, fb / fa, decimal):
222-
assert False, (f'expected {fb:.5f} but got {fa:.5f}, '
223-
f'with decimal {decimal}')
203+
if not math.isclose(fa, fb, rel_tol=rtol, abs_tol=atol):
204+
assert False, (f"expected {fb:.5f} but got {fa:.5f}, "
205+
f"with rtol={rtol}, atol={atol}")
224206
return True
225207

226208
raise AssertionError(f"{a} != {b}")

0 commit comments

Comments
 (0)