Skip to content

Commit ef59c17

Browse files
committed
predicate equality is fuzzy with float precision tolerance
1 parent 9b50baa commit ef59c17

File tree

1 file changed

+13
-5
lines changed

1 file changed

+13
-5
lines changed

datascience/predicates.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
"""Predicate functions."""
22

33
import functools
4+
import numbers
5+
import numpy as np
46

57
__all__ = ['are']
68

@@ -81,7 +83,7 @@ class are:
8183
@staticmethod
8284
def equal_to(y):
8385
"""Equal to y."""
84-
return _combinable(lambda x: x == y)
86+
return _combinable(lambda x: _equal_or_float_equal(x, y))
8587

8688
@staticmethod
8789
def above(y):
@@ -96,12 +98,12 @@ def below(y):
9698
@staticmethod
9799
def above_or_equal_to(y):
98100
"""Greater than or equal to y."""
99-
return _combinable(lambda x: x >= y)
101+
return _combinable(lambda x: x >= y or _equal_or_float_equal(x, y))
100102

101103
@staticmethod
102104
def below_or_equal_to(y):
103105
"""Less than or equal to y."""
104-
return _combinable(lambda x: x <= y)
106+
return _combinable(lambda x: x <= y or _equal_or_float_equal(x, y))
105107

106108
@staticmethod
107109
def strictly_between(y, z):
@@ -111,12 +113,12 @@ def strictly_between(y, z):
111113
@staticmethod
112114
def between(y, z):
113115
"""Greater than or equal to y and less than z."""
114-
return _combinable(lambda x: y <= x < z)
116+
return _combinable(lambda x: (y <= x < z) or _equal_or_float_equal(x, y))
115117

116118
@staticmethod
117119
def between_or_equal_to(y, z):
118120
"""Greater than or equal to y and less than or equal to z."""
119-
return _combinable(lambda x: y <= x <= z)
121+
return _combinable(lambda x: (y <= x <= z) or _equal_or_float_equal(x, y) or _equal_or_float_equal(x, z))
120122

121123
###############
122124
# Combination #
@@ -150,6 +152,12 @@ def __xor__(self, other):
150152
def _not(f):
151153
return lambda *args: -f(*args)
152154

155+
def _equal_or_float_equal(x, y):
156+
if isinstance(x, numbers.Real):
157+
return x == y or np.nextafter(x, 1) == y or np.nextafter(x, 0) == y
158+
else:
159+
return x == y
160+
153161
are.not_equal_to = _not(are.equal_to)
154162
are.not_above = are.below_or_equal_to
155163
are.not_below = are.above_or_equal_to

0 commit comments

Comments
 (0)