From 584982b2511d763da96cdbce8a0e5f97083ca527 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 18 Oct 2026 11:36:05 +0000 Subject: [PATCH 1/2] Initial plan From 76cdf5ceb740d1fe6d90b5006a31f614921e6ad7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 18 Oct 2026 11:38:10 +0000 Subject: [PATCH 2/2] Fix TiesToAway rounding just below subnormal midpoint Co-authored-by: awf <128119+awf@users.noreply.github.com> --- src/gfloat/round.py | 2 +- test/test_round_underflow.py | 21 +++++++++++++++++++-- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/gfloat/round.py b/src/gfloat/round.py index 32be3a8..4967f7d 100644 --- a/src/gfloat/round.py +++ b/src/gfloat/round.py @@ -137,7 +137,7 @@ def round_float( case RoundMode.TowardNegative: should_round_away = sign and delta > 0 case RoundMode.TiesToAway: - should_round_away = delta + 0.5 >= 1.0 + should_round_away = delta >= 0.5 case RoundMode.TiesToEven: should_round_away = delta > 0.5 or (delta == 0.5 and code_is_odd) case RoundMode.ToOdd: diff --git a/test/test_round_underflow.py b/test/test_round_underflow.py index 1c6194e..0c0ae5e 100644 --- a/test/test_round_underflow.py +++ b/test/test_round_underflow.py @@ -2,12 +2,14 @@ from typing import Callable +import math + import numpy as np import pytest -from gfloat import FormatInfo, RoundMode, decode_float, encode_float +from gfloat import FormatInfo, RoundMode, Signedness, decode_float, encode_float from gfloat import round_float, round_ndarray -from gfloat.formats import Domain, format_info_ocp_e8m0 +from gfloat.formats import Domain, format_info_ocp_e8m0, format_info_p3109 def scalar_round( @@ -41,6 +43,21 @@ def no_subnormal_format(precision: int, signed: bool = False) -> FormatInfo: ) +@pytest.mark.parametrize("rounder", [scalar_round, array_round]) +@pytest.mark.parametrize("sign", [1, -1]) +@pytest.mark.parametrize("direction", [0.0, 0.5, 1.0]) +def test_round_ties_to_away_subnormal_midpoint( + rounder: Callable, sign: int, direction: float +) -> None: + fi = format_info_p3109(8, 3, Signedness.Signed, Domain.Extended) + midpoint = fi.smallest / 2 + value = math.nextafter(midpoint, direction * fi.smallest) + expected = 0.0 if direction == 0.0 else sign * fi.smallest + actual = rounder(fi, sign * value, RoundMode.TiesToAway, False, 0) + assert actual == expected + assert np.signbit(actual) == np.signbit(expected) + + @pytest.mark.parametrize("rounder", [scalar_round, array_round]) @pytest.mark.parametrize("rnd", RoundMode) @pytest.mark.parametrize("sat", [False, True])