Sorry for the late report, but it seems that the current version has some regressions on 32-bit architectures. I can reproduce both on i686 and ARM.
============================= test session starts ==============================
platform linux -- Python 3.13.11, pytest-9.0.3, pluggy-1.6.0
rootdir: /tmp/gfloat
configfile: pyproject.toml
plugins: nbval-0.11.0
collected 42 items
test/test_encode.py FF [ 4%]
test/test_round.py ................FFFF................FFFF [100%]
=================================== FAILURES ===================================
____________________________ test_encode[binary32] _____________________________
fi = FormatInfo(name='binary32', k=32, precision=24, bias=127, is_signed=True, domain=<Domain.Extended: 2>, has_nz=True, num_high_nans=8388607, has_subnormals=True, is_twos_complement=False)
@pytest.mark.parametrize("fi", sample_formats)
def test_encode(fi: FormatInfo) -> None:
dec = lambda v: decode_float(fi, v).fval
if fi.bits <= 8:
step = 1
elif fi.bits <= 16:
step = 13
elif fi.bits <= 32:
step = 73013
elif fi.bits <= 64:
step = (73013 << 32) + 39
for i in range(0, 2**fi.bits, step):
fv = decode_float(fi, i)
code = encode_float(fi, fv.fval)
assert (i == code) or (np.isnan(fv.fval) and code == fi.code_of_nan)
fv2 = decode_float(fi, code)
np.testing.assert_equal(fv2.fval, fv.fval)
codes = np.arange(0, 2**fi.bits, step, dtype=np.uint64)
fvals = np.array([decode_float(fi, int(i)).fval for i in codes])
enc_codes = encode_ndarray(fi, fvals)
expected_codes: npt.NDArray
if fi.num_nans == 0:
assert not np.any(np.isnan(fvals))
expected_codes = codes
else:
expected_codes = np.where(np.isnan(fvals), fi.code_of_nan, codes)
> np.testing.assert_equal(enc_codes, expected_codes)
E AssertionError:
E Arrays are not equal
E
E Mismatched elements: 29297 / 58825 (49.8%)
E First 5 mismatches are at indices:
E [29413]: 18446744071562115689 (ACTUAL), 2147531369 (DESIRED)
E [29414]: 18446744071562188702 (ACTUAL), 2147604382 (DESIRED)
E [29415]: 18446744071562261715 (ACTUAL), 2147677395 (DESIRED)
E [29416]: 18446744071562334728 (ACTUAL), 2147750408 (DESIRED)
E [29417]: 18446744071562407741 (ACTUAL), 2147823421 (DESIRED)
E Max absolute difference among violations: 4294967296
E Max relative difference among violations: 1.99995556
E ACTUAL: array([ 0, 73013, 146026, ..., 4294967295, 4294967295,
E 4294967295], shape=(58825,), dtype=uint64)
E DESIRED: array([ 0, 73013, 146026, ..., 4294967295, 4294967295,
E 4294967295], shape=(58825,), dtype=uint64)
test/test_encode.py:42: AssertionError
____________________________ test_encode[binary64] _____________________________
fi = FormatInfo(name='binary64', k=64, precision=53, bias=1023, is_signed=True, domain=<Domain.Extended: 2>, has_nz=True, num_high_nans=4503599627370495, has_subnormals=True, is_twos_complement=False)
@pytest.mark.parametrize("fi", sample_formats)
def test_encode(fi: FormatInfo) -> None:
dec = lambda v: decode_float(fi, v).fval
if fi.bits <= 8:
step = 1
elif fi.bits <= 16:
step = 13
elif fi.bits <= 32:
step = 73013
elif fi.bits <= 64:
step = (73013 << 32) + 39
for i in range(0, 2**fi.bits, step):
fv = decode_float(fi, i)
code = encode_float(fi, fv.fval)
assert (i == code) or (np.isnan(fv.fval) and code == fi.code_of_nan)
fv2 = decode_float(fi, code)
np.testing.assert_equal(fv2.fval, fv.fval)
codes = np.arange(0, 2**fi.bits, step, dtype=np.uint64)
fvals = np.array([decode_float(fi, int(i)).fval for i in codes])
enc_codes = encode_ndarray(fi, fvals)
expected_codes: npt.NDArray
if fi.num_nans == 0:
assert not np.any(np.isnan(fvals))
expected_codes = codes
else:
expected_codes = np.where(np.isnan(fvals), fi.code_of_nan, codes)
> np.testing.assert_equal(enc_codes, expected_codes)
E AssertionError:
E Arrays are not equal
E
E Mismatched elements: 29398 / 58825 (50%)
E First 5 mismatches are at indices:
E [29413]: 204960135479523 (ACTUAL), 9223576996990255331 (DESIRED)
E [29414]: 518548582662410 (ACTUAL), 9223890585437438218 (DESIRED)
E [29415]: 832137029845297 (ACTUAL), 9224204173884621105 (DESIRED)
E [29416]: 1145725477028184 (ACTUAL), 9224517762331803992 (DESIRED)
E [29417]: 1459313924211071 (ACTUAL), 9224831350778986879 (DESIRED)
E Max absolute difference among violations: 9223372036854775808
E Max relative difference among violations: 0.99997778
E ACTUAL: array([ 0, 313588447182887, 627176894365774,
E ..., 18446744073709551615, 18446744073709551615,
E 18446744073709551615], shape=(58825,), dtype=uint64)
E DESIRED: array([ 0, 313588447182887, 627176894365774,
E ..., 18446744073709551615, 18446744073709551615,
E 18446744073709551615], shape=(58825,), dtype=uint64)
test/test_encode.py:42: AssertionError
____ test_stochastic_rounding_scalar_eq_array[True-32-RoundMode.Stochastic] ____
rnd = <RoundMode.Stochastic: 6>, srnumbits = 32, sat = True
@pytest.mark.parametrize(
"rnd",
(
RoundMode.Stochastic,
RoundMode.StochasticOdd,
RoundMode.StochasticFast,
RoundMode.StochasticFastest,
),
)
@pytest.mark.parametrize("srnumbits", [3, 8, 9, 16, 32])
@pytest.mark.parametrize("sat", (True, False))
def test_stochastic_rounding_scalar_eq_array(
rnd: RoundMode, srnumbits: int, sat: bool
) -> None:
fi = format_info_ocp_e5m2
v0 = decode_ndarray(fi, np.arange(255))
v1 = decode_ndarray(fi, np.arange(255) + 1)
ok = np.isfinite(v0) & np.isfinite(v1)
v0 = v0[ok]
v1 = v1[ok]
for alpha in (0, 0.3, 0.5, 0.6, 0.7, 0.9, 1.25):
v = _linterp(v0, v1, alpha)
assert np.isfinite(v).all()
> srbits = np.random.randint(0, 2**srnumbits, v.shape)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
test/test_round.py:594:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
numpy/random/mtrand.pyx:799: in numpy.random.mtrand.RandomState.randint
???
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
> ???
E ValueError: high is out of bounds for int32
numpy/random/_bounded_integers.pyx:1423: ValueError
__ test_stochastic_rounding_scalar_eq_array[True-32-RoundMode.StochasticOdd] ___
rnd = <RoundMode.StochasticOdd: 7>, srnumbits = 32, sat = True
@pytest.mark.parametrize(
"rnd",
(
RoundMode.Stochastic,
RoundMode.StochasticOdd,
RoundMode.StochasticFast,
RoundMode.StochasticFastest,
),
)
@pytest.mark.parametrize("srnumbits", [3, 8, 9, 16, 32])
@pytest.mark.parametrize("sat", (True, False))
def test_stochastic_rounding_scalar_eq_array(
rnd: RoundMode, srnumbits: int, sat: bool
) -> None:
fi = format_info_ocp_e5m2
v0 = decode_ndarray(fi, np.arange(255))
v1 = decode_ndarray(fi, np.arange(255) + 1)
ok = np.isfinite(v0) & np.isfinite(v1)
v0 = v0[ok]
v1 = v1[ok]
for alpha in (0, 0.3, 0.5, 0.6, 0.7, 0.9, 1.25):
v = _linterp(v0, v1, alpha)
assert np.isfinite(v).all()
> srbits = np.random.randint(0, 2**srnumbits, v.shape)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
test/test_round.py:594:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
numpy/random/mtrand.pyx:799: in numpy.random.mtrand.RandomState.randint
???
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
> ???
E ValueError: high is out of bounds for int32
numpy/random/_bounded_integers.pyx:1423: ValueError
__ test_stochastic_rounding_scalar_eq_array[True-32-RoundMode.StochasticFast] __
rnd = <RoundMode.StochasticFast: 8>, srnumbits = 32, sat = True
@pytest.mark.parametrize(
"rnd",
(
RoundMode.Stochastic,
RoundMode.StochasticOdd,
RoundMode.StochasticFast,
RoundMode.StochasticFastest,
),
)
@pytest.mark.parametrize("srnumbits", [3, 8, 9, 16, 32])
@pytest.mark.parametrize("sat", (True, False))
def test_stochastic_rounding_scalar_eq_array(
rnd: RoundMode, srnumbits: int, sat: bool
) -> None:
fi = format_info_ocp_e5m2
v0 = decode_ndarray(fi, np.arange(255))
v1 = decode_ndarray(fi, np.arange(255) + 1)
ok = np.isfinite(v0) & np.isfinite(v1)
v0 = v0[ok]
v1 = v1[ok]
for alpha in (0, 0.3, 0.5, 0.6, 0.7, 0.9, 1.25):
v = _linterp(v0, v1, alpha)
assert np.isfinite(v).all()
> srbits = np.random.randint(0, 2**srnumbits, v.shape)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
test/test_round.py:594:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
numpy/random/mtrand.pyx:799: in numpy.random.mtrand.RandomState.randint
???
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
> ???
E ValueError: high is out of bounds for int32
numpy/random/_bounded_integers.pyx:1423: ValueError
_ test_stochastic_rounding_scalar_eq_array[True-32-RoundMode.StochasticFastest] _
rnd = <RoundMode.StochasticFastest: 9>, srnumbits = 32, sat = True
@pytest.mark.parametrize(
"rnd",
(
RoundMode.Stochastic,
RoundMode.StochasticOdd,
RoundMode.StochasticFast,
RoundMode.StochasticFastest,
),
)
@pytest.mark.parametrize("srnumbits", [3, 8, 9, 16, 32])
@pytest.mark.parametrize("sat", (True, False))
def test_stochastic_rounding_scalar_eq_array(
rnd: RoundMode, srnumbits: int, sat: bool
) -> None:
fi = format_info_ocp_e5m2
v0 = decode_ndarray(fi, np.arange(255))
v1 = decode_ndarray(fi, np.arange(255) + 1)
ok = np.isfinite(v0) & np.isfinite(v1)
v0 = v0[ok]
v1 = v1[ok]
for alpha in (0, 0.3, 0.5, 0.6, 0.7, 0.9, 1.25):
v = _linterp(v0, v1, alpha)
assert np.isfinite(v).all()
> srbits = np.random.randint(0, 2**srnumbits, v.shape)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
test/test_round.py:594:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
numpy/random/mtrand.pyx:799: in numpy.random.mtrand.RandomState.randint
???
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
> ???
E ValueError: high is out of bounds for int32
numpy/random/_bounded_integers.pyx:1423: ValueError
___ test_stochastic_rounding_scalar_eq_array[False-32-RoundMode.Stochastic] ____
rnd = <RoundMode.Stochastic: 6>, srnumbits = 32, sat = False
@pytest.mark.parametrize(
"rnd",
(
RoundMode.Stochastic,
RoundMode.StochasticOdd,
RoundMode.StochasticFast,
RoundMode.StochasticFastest,
),
)
@pytest.mark.parametrize("srnumbits", [3, 8, 9, 16, 32])
@pytest.mark.parametrize("sat", (True, False))
def test_stochastic_rounding_scalar_eq_array(
rnd: RoundMode, srnumbits: int, sat: bool
) -> None:
fi = format_info_ocp_e5m2
v0 = decode_ndarray(fi, np.arange(255))
v1 = decode_ndarray(fi, np.arange(255) + 1)
ok = np.isfinite(v0) & np.isfinite(v1)
v0 = v0[ok]
v1 = v1[ok]
for alpha in (0, 0.3, 0.5, 0.6, 0.7, 0.9, 1.25):
v = _linterp(v0, v1, alpha)
assert np.isfinite(v).all()
> srbits = np.random.randint(0, 2**srnumbits, v.shape)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
test/test_round.py:594:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
numpy/random/mtrand.pyx:799: in numpy.random.mtrand.RandomState.randint
???
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
> ???
E ValueError: high is out of bounds for int32
numpy/random/_bounded_integers.pyx:1423: ValueError
__ test_stochastic_rounding_scalar_eq_array[False-32-RoundMode.StochasticOdd] __
rnd = <RoundMode.StochasticOdd: 7>, srnumbits = 32, sat = False
@pytest.mark.parametrize(
"rnd",
(
RoundMode.Stochastic,
RoundMode.StochasticOdd,
RoundMode.StochasticFast,
RoundMode.StochasticFastest,
),
)
@pytest.mark.parametrize("srnumbits", [3, 8, 9, 16, 32])
@pytest.mark.parametrize("sat", (True, False))
def test_stochastic_rounding_scalar_eq_array(
rnd: RoundMode, srnumbits: int, sat: bool
) -> None:
fi = format_info_ocp_e5m2
v0 = decode_ndarray(fi, np.arange(255))
v1 = decode_ndarray(fi, np.arange(255) + 1)
ok = np.isfinite(v0) & np.isfinite(v1)
v0 = v0[ok]
v1 = v1[ok]
for alpha in (0, 0.3, 0.5, 0.6, 0.7, 0.9, 1.25):
v = _linterp(v0, v1, alpha)
assert np.isfinite(v).all()
> srbits = np.random.randint(0, 2**srnumbits, v.shape)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
test/test_round.py:594:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
numpy/random/mtrand.pyx:799: in numpy.random.mtrand.RandomState.randint
???
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
> ???
E ValueError: high is out of bounds for int32
numpy/random/_bounded_integers.pyx:1423: ValueError
_ test_stochastic_rounding_scalar_eq_array[False-32-RoundMode.StochasticFast] __
rnd = <RoundMode.StochasticFast: 8>, srnumbits = 32, sat = False
@pytest.mark.parametrize(
"rnd",
(
RoundMode.Stochastic,
RoundMode.StochasticOdd,
RoundMode.StochasticFast,
RoundMode.StochasticFastest,
),
)
@pytest.mark.parametrize("srnumbits", [3, 8, 9, 16, 32])
@pytest.mark.parametrize("sat", (True, False))
def test_stochastic_rounding_scalar_eq_array(
rnd: RoundMode, srnumbits: int, sat: bool
) -> None:
fi = format_info_ocp_e5m2
v0 = decode_ndarray(fi, np.arange(255))
v1 = decode_ndarray(fi, np.arange(255) + 1)
ok = np.isfinite(v0) & np.isfinite(v1)
v0 = v0[ok]
v1 = v1[ok]
for alpha in (0, 0.3, 0.5, 0.6, 0.7, 0.9, 1.25):
v = _linterp(v0, v1, alpha)
assert np.isfinite(v).all()
> srbits = np.random.randint(0, 2**srnumbits, v.shape)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
test/test_round.py:594:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
numpy/random/mtrand.pyx:799: in numpy.random.mtrand.RandomState.randint
???
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
> ???
E ValueError: high is out of bounds for int32
numpy/random/_bounded_integers.pyx:1423: ValueError
_ test_stochastic_rounding_scalar_eq_array[False-32-RoundMode.StochasticFastest] _
rnd = <RoundMode.StochasticFastest: 9>, srnumbits = 32, sat = False
@pytest.mark.parametrize(
"rnd",
(
RoundMode.Stochastic,
RoundMode.StochasticOdd,
RoundMode.StochasticFast,
RoundMode.StochasticFastest,
),
)
@pytest.mark.parametrize("srnumbits", [3, 8, 9, 16, 32])
@pytest.mark.parametrize("sat", (True, False))
def test_stochastic_rounding_scalar_eq_array(
rnd: RoundMode, srnumbits: int, sat: bool
) -> None:
fi = format_info_ocp_e5m2
v0 = decode_ndarray(fi, np.arange(255))
v1 = decode_ndarray(fi, np.arange(255) + 1)
ok = np.isfinite(v0) & np.isfinite(v1)
v0 = v0[ok]
v1 = v1[ok]
for alpha in (0, 0.3, 0.5, 0.6, 0.7, 0.9, 1.25):
v = _linterp(v0, v1, alpha)
assert np.isfinite(v).all()
> srbits = np.random.randint(0, 2**srnumbits, v.shape)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
test/test_round.py:594:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
numpy/random/mtrand.pyx:799: in numpy.random.mtrand.RandomState.randint
???
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
> ???
E ValueError: high is out of bounds for int32
numpy/random/_bounded_integers.pyx:1423: ValueError
=============================== warnings summary ===============================
test/test_round.py: 27520 warnings
/tmp/gfloat/src/gfloat/round.py:23: DeprecationWarning: Bitwise inversion '~' on bool is deprecated and will be removed in Python 3.16. This returns the bitwise inversion of the underlying int object and is usually not what you expect from negating a bool. Use the 'not' operator for boolean negation or ~int(x) if you really want the bitwise inversion of the underlying int.
should_round_away = (x > floored + 0.5) | ((x == floored + 0.5) & ~pred(floored))
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED test/test_encode.py::test_encode[binary32] - AssertionError:
FAILED test/test_encode.py::test_encode[binary64] - AssertionError:
FAILED test/test_round.py::test_stochastic_rounding_scalar_eq_array[True-32-RoundMode.Stochastic]
FAILED test/test_round.py::test_stochastic_rounding_scalar_eq_array[True-32-RoundMode.StochasticOdd]
FAILED test/test_round.py::test_stochastic_rounding_scalar_eq_array[True-32-RoundMode.StochasticFast]
FAILED test/test_round.py::test_stochastic_rounding_scalar_eq_array[True-32-RoundMode.StochasticFastest]
FAILED test/test_round.py::test_stochastic_rounding_scalar_eq_array[False-32-RoundMode.Stochastic]
FAILED test/test_round.py::test_stochastic_rounding_scalar_eq_array[False-32-RoundMode.StochasticOdd]
FAILED test/test_round.py::test_stochastic_rounding_scalar_eq_array[False-32-RoundMode.StochasticFast]
FAILED test/test_round.py::test_stochastic_rounding_scalar_eq_array[False-32-RoundMode.StochasticFastest]
================ 10 failed, 32 passed, 27520 warnings in 32.12s ================
Sorry for the late report, but it seems that the current version has some regressions on 32-bit architectures. I can reproduce both on i686 and ARM.