Skip to content

BUG: int to np.float32 conversion is not correctly rounded #20687

@mdickinson

Description

@mdickinson

Describe the issue:

Conversion from a Python int to an np.float32 value does not appear to be correctly rounded, and does not always match the equivalent conversion from np.int64 to np.float32.

I'm a bit hesitant to call this a bug rather than a feature request, since I'm not aware of anywhere where it's specified that int to np.float32 conversions should be correctly rounded. But whether bug or not, correct rounding seems like a desirable property here, and consistency between int and np.int64 also seems desirable.

In IEEE 754 binary32 floating-point, 2**54 - 2**30 and 2**54 are both exactly representable, and are neighboring floating-point values. The halfway point between them is 2**54 - 2**29. Under correct rounding (ties-to-even, as usual), integers n in the interval [2**54 - 2**29, 2**54) should round up to 2**54 when converted to np.float32, while integers in (2**54-2**30, 2**54-2**29) should round down to 2**54 - 2**30. In particular, 2**54 - 2**29 - 1 should round down, but as the code example below shows, it rounds up.

In contrast, the exact same input value represented as an int64 instead of an int rounds down (as expected).

I haven't looked at the implementation, but my strong suspicion is that there's a double rounding going on here: that the incoming int is converted first to float64, and then to float32.

Reproduce the code example:

>>> import numpy as np
>>> np.float32(2**54 - 2**29 - 1) == 2**54 - 2**30  # expect True, get False
False
>>> np.float32(np.int64(2**54 - 2**29 - 1)) == 2**54 - 2**30  # ok: expect True, get True
True

Second example, to emphasise the unexpected difference in behaviour between int and np.int64:

>>> import numpy as np
>>> x = 2**54 - 2**29 - 1
>>> y = np.int64(x)
>>> x == y
True
>>> np.float32(x) == np.float32(y)  # expect True, get False
False

Error message:

No response

NumPy/Python version information:

>>> import sys, numpy
>>> print(numpy.__version__)
1.21.4
>>> print(sys.version)
3.9.9 (main, Nov 16 2021, 07:23:17) 
[Clang 10.0.1 (clang-1001.0.46.4)]

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions