Skip to content

Instantly share code, notes, and snippets.

@matthiasgoergens
Last active April 25, 2023 11:36
Show Gist options
  • Select an option

  • Save matthiasgoergens/28e58abd6beaea72bd2e49085c435966 to your computer and use it in GitHub Desktop.

Select an option

Save matthiasgoergens/28e58abd6beaea72bd2e49085c435966 to your computer and use it in GitHub Desktop.

Revisions

  1. matthiasgoergens revised this gist Apr 25, 2023. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions nextafter.py
    Original file line number Diff line number Diff line change
    @@ -72,7 +72,7 @@ def test(start, goal, steps):
    soll = nextafter_reduce(start, goal, steps)
    ist = my_nextafter_steps(start, goal, steps)
    note(f"{soll} != {ist}")
    assert math.isnan(soll) == math.isnan(ist) or soll == ist
    assert math.isnan(soll) and math.isnan(ist) or soll == ist


    @given(
    @@ -86,7 +86,7 @@ def test_goal2(start, goal, steps1, steps2):
    soll = nextafter_reduce(start, goal1, steps2)
    ist = my_nextafter_steps(start, goal1, steps2)
    note(f"{soll} != {ist}")
    assert (math.isnan(soll) and math.isnan(ist)) or soll == ist
    assert math.isnan(soll) and math.isnan(ist) or soll == ist


    if __name__ == "__main__":
  2. matthiasgoergens revised this gist Apr 25, 2023. 1 changed file with 10 additions and 4 deletions.
    14 changes: 10 additions & 4 deletions nextafter.py
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,7 @@
    import math
    import struct
    from functools import reduce
    from itertools import repeat

    from hypothesis import assume, example, given, note
    from hypothesis import strategies as st
    @@ -13,6 +15,10 @@ def float_to_integer(float):
    return struct.unpack("!Q", struct.pack("!d", float))[0]


    def nextafter_reduce(start, goal, steps):
    return reduce(math.nextafter, repeat(goal, steps), start)


    def nextafter_loop(start, goal, steps):
    for _ in range(steps):
    start = math.nextafter(start, goal)
    @@ -63,7 +69,7 @@ def my_nextafter_steps(start, goal, steps):
    steps=st.integers(min_value=0, max_value=1_000_000),
    )
    def test(start, goal, steps):
    soll = nextafter_loop(start, goal, steps)
    soll = nextafter_reduce(start, goal, steps)
    ist = my_nextafter_steps(start, goal, steps)
    note(f"{soll} != {ist}")
    assert math.isnan(soll) == math.isnan(ist) or soll == ist
    @@ -76,11 +82,11 @@ def test(start, goal, steps):
    steps2=st.integers(min_value=0, max_value=1_000_000),
    )
    def test_goal2(start, goal, steps1, steps2):
    goal1 = nextafter_loop(start, goal, steps1)
    soll = nextafter_loop(start, goal1, steps2)
    goal1 = nextafter_reduce(start, goal, steps1)
    soll = nextafter_reduce(start, goal1, steps2)
    ist = my_nextafter_steps(start, goal1, steps2)
    note(f"{soll} != {ist}")
    assert math.isnan(soll) == math.isnan(ist) or soll == ist
    assert (math.isnan(soll) and math.isnan(ist)) or soll == ist


    if __name__ == "__main__":
  3. matthiasgoergens revised this gist Aug 15, 2022. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion nextafter.py
    Original file line number Diff line number Diff line change
    @@ -19,7 +19,7 @@ def nextafter_loop(start, goal, steps):
    return start


    # TODO: Think about support negative steps.
    # TODO: Think about supporting negative steps?
    def my_nextafter_steps(start, goal, steps):
    # We only check for zero steps, so that
    # nextafter(start, nan, 0) returns start,
  4. matthiasgoergens created this gist Aug 15, 2022.
    88 changes: 88 additions & 0 deletions nextafter.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,88 @@
    import math
    import struct

    from hypothesis import assume, example, given, note
    from hypothesis import strategies as st


    def float_from_integer(integer):
    return struct.unpack("!d", struct.pack("!Q", integer))[0]


    def float_to_integer(float):
    return struct.unpack("!Q", struct.pack("!d", float))[0]


    def nextafter_loop(start, goal, steps):
    for _ in range(steps):
    start = math.nextafter(start, goal)
    return start


    # TODO: Think about support negative steps.
    def my_nextafter_steps(start, goal, steps):
    # We only check for zero steps, so that
    # nextafter(start, nan, 0) returns start,
    # instead of giving nan.
    if steps == 0:
    return start
    if math.isnan(start) or math.isnan(goal):
    return math.nan

    if math.copysign(1, start) < 0:
    return -my_nextafter_steps(-start, -goal, steps)
    assert start >= 0

    if math.copysign(1, goal) < 0:
    i = float_to_integer(start)
    if steps > i:
    return -my_nextafter_steps(0.0, -goal, steps - i)
    else:
    # Setting goal to 0 ain't necessary, but makes the invariants
    # further down simpler to explain
    goal = 0.0
    assert start >= 0 and goal >= 0 and steps > 0

    if start < goal:
    steps = steps
    cmp = min
    elif start == goal:
    return start
    else:
    steps = -steps
    cmp = max
    return float_from_integer(
    cmp(float_to_integer(goal), steps + float_to_integer(start))
    )


    @example(start=1.0, goal=math.nextafter(1.0, math.inf), steps=10)
    @given(
    start=st.floats(),
    goal=st.floats(),
    steps=st.integers(min_value=0, max_value=1_000_000),
    )
    def test(start, goal, steps):
    soll = nextafter_loop(start, goal, steps)
    ist = my_nextafter_steps(start, goal, steps)
    note(f"{soll} != {ist}")
    assert math.isnan(soll) == math.isnan(ist) or soll == ist


    @given(
    start=st.floats(),
    goal=st.floats(),
    steps1=st.integers(min_value=0, max_value=1_000_000),
    steps2=st.integers(min_value=0, max_value=1_000_000),
    )
    def test_goal2(start, goal, steps1, steps2):
    goal1 = nextafter_loop(start, goal, steps1)
    soll = nextafter_loop(start, goal1, steps2)
    ist = my_nextafter_steps(start, goal1, steps2)
    note(f"{soll} != {ist}")
    assert math.isnan(soll) == math.isnan(ist) or soll == ist


    if __name__ == "__main__":
    test()
    test_goal2()