Skip to content

Commit

Permalink
properly clamp signed zeroes
Browse files Browse the repository at this point in the history
  • Loading branch information
tybug committed Dec 23, 2024
1 parent 9fa1801 commit 7cdeb91
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,13 @@ def __underlying_index(self, i: int) -> int:
def clamp(lower: float, value: float, upper: float) -> float:
"""Given a value and lower/upper bounds, 'clamp' the value so that
it satisfies lower <= value <= upper."""
# this seems pointless (and is for integers), but handles the -0.0/0.0 case.
# clamp(-1, 0.0, -0.0) violates the bounds by returning 0.0, since min(0.0, -0.0)
# takes the first value of 0.0.
if value == lower:
return lower
if value == upper:
return upper
return max(lower, min(value, upper))


Expand Down
19 changes: 11 additions & 8 deletions hypothesis-python/tests/conjecture/test_junkdrawer.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
stack_depth_of_caller,
startswith,
)
from hypothesis.internal.floats import float_to_int, sign_aware_lte


def test_out_of_range():
Expand Down Expand Up @@ -66,20 +67,22 @@ def test_pop():
@example(1, 10, 5)
@example(5, 10, 5)
@example(5, 1, 10)
@given(st.integers(), st.integers(), st.integers())
@example(-5, 0.0, -0.0)
@example(0.0, -0.0, 5)
@given(
st.floats(allow_nan=False), st.floats(allow_nan=False), st.floats(allow_nan=False)
)
def test_clamp(lower, value, upper):
lower, upper = sorted((lower, upper))

clamped = clamp(lower, value, upper)

assert lower <= clamped <= upper

if lower <= value <= upper:
assert value == clamped
assert sign_aware_lte(lower, clamped) and sign_aware_lte(clamped, upper)
if sign_aware_lte(lower, value) and sign_aware_lte(value, upper):
assert float_to_int(value) == float_to_int(clamped)
if lower > value:
assert clamped == lower
assert float_to_int(clamped) == float_to_int(lower)
if value > upper:
assert clamped == upper
assert float_to_int(clamped) == float_to_int(upper)


# this would be more robust as a stateful test, where each rule is a list operation
Expand Down
1 change: 1 addition & 0 deletions hypothesis-python/tests/cover/test_float_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ def test_next_float_equal(func, val):
@example(float_kw(1, 4, smallest_nonzero_magnitude=4), -4)
@example(float_kw(1, 4, smallest_nonzero_magnitude=4), -5)
@example(float_kw(1, 4, smallest_nonzero_magnitude=4), -6)
@example(float_kw(-5e-324, -0.0, smallest_nonzero_magnitude=5e-324), 3.0)
@given(float_kwargs(), st.floats())
def test_float_clamper(kwargs, input_value):
min_value = kwargs["min_value"]
Expand Down

0 comments on commit 7cdeb91

Please sign in to comment.