Daniele Bigoni
Daniele Bigoni

Reputation: 131

numpy.int64 times int -> numpy.float64

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

Answers (2)

SeF
SeF

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

be_good_do_good
be_good_do_good

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 as 9223372036854775808L

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 as 9223372036854775807

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 returns 9.2233720368547758e+18, as you see it is represented in decimals in Euler's form.

type(b*a) returns np.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

Related Questions