-
-
Notifications
You must be signed in to change notification settings - Fork 10.8k
BUG: Binary operations between uint64 and intX results in float64 #20905
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
I am working on this @paigeweber13 |
@soma2000-lang I just discovered bug report #5745, which is almost identical. The only difference is that in my case the operator is |
Sounds like it needs a decent proposal for what to do with We could even consider just adding a warning when this type of promotion happens (that should be very simple)... But, I personally don't have a very clear gut feeling on what we should do, and I have currently more important things to lose sanity over :). |
I would deeply appreciate a warning of some kind, as well as some clear documentation on when type coercions happen. I spent a full workday chasing down this behavior. I'd be willing to write up an MR for improved documentation, if you can point me to the code where type coercions happen. Personally I'd like |
This is the place that it is defined: numpy/numpy/core/src/multiarray/dtypemeta.c Lines 382 to 406 in 23dfdfc
Which just looks it up in another place that is a funny generated table though. In any case, that is the place where you would have to change it (by introducing a new function probably, and using that for |
If I have time this week I'll take a look. I'm going to start with documentation so other people that experience this issue at least have a reference for what is expected |
Fraction
from numpy integer types coerces types to numpy.float64
Option 1) from seibert in #5745 seems like the obvious thing to do. Follow C/C++ and let However, the lower-bit scalars all promote to the next higher signed integer type, e.g.
|
The Python int looks like a reasonable fix. It would also fit in with the proposal for typed object arrays, that is, arrays that only contain one type of object. |
Also found out about this recently. My two cents: I would object converting to int being inherently better than converting to float. I would say, in the case of
|
This is not required when compiled with numba see numpy/numpy#20905
This is not required when compiled with numba see numpy/numpy#20905
This is not required when compiled with numba see numpy/numpy#20905
#23476 is a variation on the theme. +1 to for the proposal mentioned above to follow the C/C++ behavior. |
Until I found this issue I was promoting numpy as a strictly typed alternative to the nonsense of matlab. Please stop proving me wrong. |
We've never advertised ourselves as strictly-typed, whatever that means to you. We have types with promotion rules, most of which are fairly reasonable, but some dark corners where there aren't many obviously great alternatives (and it's not clear to me that raising an exception to be "strictly-typed" here is a better alternative, though one could certainly argue the point). |
Well point is that there are certain rules about type conversion in Python. Int should not magically turn into float when added to another int, for example. Quietly coercing uint64+uint64 to float64 is not just inappropriate from the point of view of possible overflow/loss of precision, but is also the kind of loose type magic that terrible commercial tools like matlab really like. However, in this particular case numpy is clearly behind: >>> a=np.array([2**64-1],dtype=np.uint64)
>>> int(a[0]-1) == int((a-1)[0])
False # I would expect a True here For comparison, the abominable Matlab gets this one correct, and preserves the type of the resulting array as expected >> uint64(42) +1
ans =
uint64
43
>> a=[uint64(2)^63 ];
>> b= a-1
b =
uint64
9223372036854775807
>> b(1) == (a(1)-1)
ans =
logical
1 PS: Matlab has other, more serious problems, of course: >> uint64(5) -uint64(7)
ans =
uint64
0 |
@alexpyattaev Just a note, I think this particular issue (adding I understand your frustration here: uint64/int64 promotion is an unfortunate corner case in NumPy's documented type promotion semantics, but it's something that has been baked-in for a quarter century now. Making that kind of backward-incompatible change is a rather arduous process, for good reason: stability in tools like NumPy is hugely important to the various communities that depend on them. But the community of numpy developers is thinking about these things and how they can be improved. |
Maybe it would be nice to have this issue a warning? This way current users can know about possible bugs (I doubt anyone is relying on this sort of promotion in production). Making this an error is not even necessary as long as there is a way to actually run the math operations in uint64 that is reliable. This would keep backwards compatibility while enabling this to get fixed eventually. |
Describe the issue:
Expected Behavior:
I expect to create a python
Fraction
from numpy integer types with no loss of precisionActual Behavior:
Types are coerced to
numpy.float64
and precision is lostReproducible code example:
Error message:
No response
NumPy/Python version information:
Numpy: 1.21.2
Python: 3.7.9 (default, Aug 31 2020, 12:42:55) [GCC 7.3.0]
OS: Debian GNU/Linux 10 (buster)
Other information that may be helpful:
I discovered this behavior while creating fractions from parallel arrays representing the numerators and denominators of fractions. This loss of precision is problematic because the float is rounded up so that it is out of range for
uint64
, despite the original value being valid. In my case I have a workaround, as converting the values to pythonint
before inputting them to theFraction
constructor prevents this issue. However, I wanted to let you know because it is unexpected that an operation with two numpy integer types produced a value with floating point types.I briefly looked into the
Fractions
constructor and I discovered that this behavior comes from lines 175-180 offractions.py
:numpy.uint64
is an instance ofnumbers.Rational
:Inspecting the reproducible snippet above with
pdb
reveals that the multiplication on lines 178-179 offractions.py
is the moment when the type is changed.Thank you for your time (:
The text was updated successfully, but these errors were encountered: