13

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?

7
  • 2
    Is there any reasonable explanation for it? Yes, it is value range magnitude handling. Commented Mar 10, 2016 at 22:21
  • I see, but I find it strange that the type is correctly casted to long when the integer is increased to 92233720368547758100. So, is "long" the only safe way to go for handling long numbers? Commented Mar 10, 2016 at 22:38
  • 2
    From the documentation docs.python.org/2/library/… , Long integers have unlimited precision. Probably it is an efficiency choice: floats have limited precision and range, but they are computationally fast. Unlimited precision longs may be very expensive to perform arithmetic on, so casting is reasonable to explicitly ask for that tradeoff. Commented Mar 10, 2016 at 22:46
  • Is this an expected behaviour anyway or should I file a bug? Commented Mar 11, 2016 at 14:11
  • 1
    I just filed a bug. Follow the discussion here: github.com/numpy/numpy/issues/7409 Commented Mar 11, 2016 at 20:01

2 Answers 2

1

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

Sign up to request clarification or add additional context in comments.

Comments

0

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.