Reputation: 131
I'm using python3 with numpy version 1.8.2 (same issue with numpy 1.10.4 and python2) and trying to do something very basic: multiplying two integers.
import numpy as np
a = 9223372036854775808
type(a)
b = np.int64(0)
type(b)
type(b*a)
The output is however:
builtins.int
numpy.int64
numpy.float64
So the multiplication of two integers returns a float! Is there any reasonable explanation for it?
Note that if I change to
a = 9223372036854775807
type(b*a)
returns
numpy.int64
And if I raise it to
a = 92233720368547758100
type(b*a)
returns (in python3)
builtins.int
and (in python2)
long
As I understand there must be some overflow, but why?
Upvotes: 13
Views: 3024
Reputation: 4160
This answer is not really an answer: is an attempt to try understand the issue better!
With Python 2.7.13 I got
In [24]: a = 9223372036854775808; type(a)
Out[24]: long
While in python 3.6.0 I got
In [24]: a = 9223372036854775808; type(a)
Out[24]: int
And this is coherent with the fact that long are still called int even if behaving like long in Python3.
Can this be part of the problem of the reported bug? If we stay on Python2, can what you saw be a bug of numpy in querying the type of a value stored in a variable when performing a multiplication? Consider
In [11]: type(int(9223372036854775807))
Out[11]: int
In [12]: type(int(9223372036854775808))
Out[12]: long
In [13]: a = 9223372036854775808
In [14]: b = np.int64(0)
In [15]: type(9223372036854775808 * np.int64(0))
Out[15]: long
In [16]: type(b*a)
Out[16]: numpy.float64
In [17]: type(long(9223372036854775808) * np.int64(0))
Out[17]: long
In [18]: type(int(9223372036854775808) * np.int64(0))
Out[18]: long
In [19]: type(np.int64(9223372036854775808) * np.int64(0))
---------------------------------------------------------------------------
OverflowError Traceback (most recent call last)
<ipython-input-18-93a64125698a> in <module>()
----> 1 type(np.int64(9223372036854775808) * np.int64(0))
OverflowError: Python int too large to convert to C long
The number 9223372036854775808 is stored as long.
Line 15 the processor says "long times int64 is long as it is the biggest container".
Line 16 the processor sees a as int and said "int times np.int64 is np.int64 as I prefer to store it in a numpy type, since you call it, but wait... 9223372036854775808 cannot stay in int64, so I am in trouble now (unexpected trouble, as it not happen when using only numpy type - line 19). I then put myself in "trouble mode" storing the results by default in the largest numpy container I have, which is float64".
In Python3 lines 15 and 16 behaves differently: numpy goes always in "trouble mode" as the long type is always detected as an int:
In [10]: type(9223372036854775808 + np.int64(0))
Out[10]: numpy.float64
In [11]: type(a*b)
Out[11]: numpy.float64
Upvotes: 0
Reputation: 4441
Actually it is very good observation and question. Here is the quick analogy:
import numpy as np
a = 9223372036854775808
Note that you are crossing the int
limit, it is entering the long int
range
a
will produce output as9223372036854775808L
type(a)
will produce output as<type 'long'>
In the below case, we are staying with in the int
limit
a = 9223372036854775807
Here
a
returns output as9223372036854775807
type(a) returns output as
<type 'int'>
let us assume b = np.int64(1)
for instance. I will explain in while why I took np.int64(1)
instead of np.int64(0)
b*a
returns9.2233720368547758e+18
, as you see it is represented in decimals in Euler's form.
type(b*a)
returnsnp.float64
Hence for the above reason, it is converted to float i.e., np.float(64). Eulers form of number always needs float/decimal points for its representation
Reason for considering b
as np.int64(1)
: If it was np.int64(0)
, you will never notice the output as the result will be all 0s
Upvotes: 1