11"""Predicate functions."""
22
33import 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):
150152def _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+
153161are .not_equal_to = _not (are .equal_to )
154162are .not_above = are .below_or_equal_to
155163are .not_below = are .above_or_equal_to
0 commit comments