Skip to content

Commit f769bfe

Browse files
committed
Merge remote-tracking branch 'upstream/master' into type-conjecture
2 parents 57e8cf1 + ef5ec3c commit f769bfe

File tree

10 files changed

+210
-146
lines changed

10 files changed

+210
-146
lines changed

AUTHORS.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ their individual contributions.
120120
* `Pax (R. Margret) W. <https://github.com/paxcodes>`_
121121
* `Peadar Coyle <https://github.com/springcoil>`_ ([email protected])
122122
* `Petr Viktorin <https://github.com/encukou>`_
123+
* `Phillip Schanely <https://github.com/pschanely>`_ ([email protected])
123124
* `Pierre-Jean Campigotto <https://github.com/PJCampi>`_
124125
* `Przemek Konopko <https://github.com/soutys>`_
125126
* `Richard Boulton <https://www.github.com/rboulton>`_ ([email protected])

hypothesis-python/RELEASE.rst

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,14 @@
11
RELEASE_TYPE: patch
22

33
This patch by Adrian Garcia Badaracco adds type annotations
4-
to some private internals (:issue:`3074`).
4+
to some private internals (:issue:`3074`).
5+
6+
This patch by Phillip Schanely makes changes to the
7+
:func:`~hypothesis.strategies.floats` strategy when ``min_value`` or ``max_value`` is
8+
present.
9+
Hypothesis will now be capable of generating every representable value in the bounds.
10+
You may notice that hypothesis is more likely to test values near boundaries, and values
11+
that are very close to zero.
12+
13+
These changes also support future integrations with symbolic execution tools and fuzzers
14+
(:issue:`3086`).

hypothesis-python/src/hypothesis/internal/conjecture/floats.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
# obtain one at https://mozilla.org/MPL/2.0/.
1010

1111
from array import array
12-
from typing import TYPE_CHECKING
12+
from typing import TYPE_CHECKING, Optional
1313

1414
from hypothesis.internal.conjecture.utils import calc_label_from_name
1515
from hypothesis.internal.floats import float_to_int, int_to_float
@@ -226,18 +226,17 @@ def is_simple(f: float) -> int:
226226
return i.bit_length() <= 56
227227

228228

229-
def draw_float(data: "ConjectureData") -> float:
229+
def draw_float(data: "ConjectureData", forced_sign_bit: Optional[int] = None) -> float:
230230
try:
231231
data.start_example(DRAW_FLOAT_LABEL)
232+
is_negative = data.draw_bits(1, forced=forced_sign_bit)
232233
f = lex_to_float(data.draw_bits(64))
233-
if data.draw_bits(1):
234-
f = -f
235-
return f
234+
return -f if is_negative else f
236235
finally:
237236
data.stop_example()
238237

239238

240239
def write_float(data: "ConjectureData", f: float) -> None:
241-
data.draw_bits(64, forced=float_to_lex(abs(f)))
242240
sign = float_to_int(f) >> 63
243241
data.draw_bits(1, forced=sign)
242+
data.draw_bits(64, forced=float_to_lex(abs(f)))

hypothesis-python/src/hypothesis/internal/conjecture/shrinker.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1072,12 +1072,12 @@ def minimize_floats(self, chooser):
10721072
lambda ex: (
10731073
ex.label == DRAW_FLOAT_LABEL
10741074
and len(ex.children) == 2
1075-
and ex.children[0].length == 8
1075+
and ex.children[1].length == 8
10761076
),
10771077
)
10781078

1079-
u = ex.children[0].start
1080-
v = ex.children[0].end
1079+
u = ex.children[1].start
1080+
v = ex.children[1].end
10811081
buf = self.shrink_target.buffer
10821082
b = buf[u:v]
10831083
f = lex_to_float(int_from_bytes(b))

hypothesis-python/src/hypothesis/internal/floats.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import math
1212
import struct
1313
from sys import float_info
14+
from typing import Callable, Optional
1415

1516
# Format codes for (int, float) sized types, used for byte-wise casts.
1617
# See https://docs.python.org/3/library/struct.html#format-characters
@@ -117,3 +118,37 @@ def next_up_normal(value, width, allow_subnormal):
117118
64: 2 ** -(2 ** (11 - 1) - 2),
118119
}
119120
assert width_smallest_normals[64] == float_info.min
121+
122+
123+
def make_float_clamper(
124+
min_float: float = 0.0,
125+
max_float: float = math.inf,
126+
allow_zero: bool = False, # Allows +0.0 (even if minfloat > 0)
127+
) -> Optional[Callable[[float], float]]:
128+
"""
129+
Return a function that clamps positive floats into the given bounds.
130+
131+
Returns None when no values are allowed (min > max and zero is not allowed).
132+
"""
133+
if max_float < min_float:
134+
if allow_zero:
135+
min_float = max_float = 0.0
136+
else:
137+
return None
138+
139+
range_size = min(max_float - min_float, float_info.max)
140+
mantissa_mask = (1 << 52) - 1
141+
142+
def float_clamper(float_val: float) -> float:
143+
if min_float <= float_val <= max_float:
144+
return float_val
145+
if float_val == 0.0 and allow_zero:
146+
return float_val
147+
# Outside bounds; pick a new value, sampled from the allowed range,
148+
# using the mantissa bits.
149+
mant = float_to_int(float_val) & mantissa_mask
150+
float_val = min_float + range_size * (mant / mantissa_mask)
151+
# Re-enforce the bounds (just in case of floating point arithmetic error)
152+
return max(min_float, min(max_float, float_val))
153+
154+
return float_clamper

0 commit comments

Comments
 (0)