Numpy.int64 раз int → numpy.float64

Я использую python3 с numpy версии 1.8.2 (эта же проблема с numpy 1.10.4 и python2) и пытаюсь сделать что-то очень основное: умножая два целых числа.

import numpy as np
a = 9223372036854775808
type(a)
b = np.int64(0)
type(b)
type(b*a)

Выход:

builtins.int
numpy.int64
numpy.float64

Таким образом, умножение двух целых чисел возвращает float! Есть ли разумное объяснение?

Обратите внимание, что если я перейду на

a = 9223372036854775807
type(b*a)

возвращает

numpy.int64

И если я подниму его на

a = 92233720368547758100
type(b*a)

возвращает (в python3)

builtins.int

и (в python2)

long

Как я понимаю, должно быть какое-то переполнение, но почему?

Ответ 1

На самом деле это очень хорошее наблюдение и вопрос. Вот быстрая аналогия:

import numpy as np

a = 9223372036854775808

Обратите внимание, что вы пересекаете предел int, он вводит диапазон long int

a будет выдавать результат как 9223372036854775808L

type(a) будет выдавать результат как <type 'long'>

В приведенном ниже случае мы остановимся в пределе int

a = 9223372036854775807

Здесь a возвращает вывод как 9223372036854775807

type (a) возвращает выходные данные как <type 'int'>

допустим, например, b = np.int64(1). Я объясню, почему я взял np.int64(1) вместо np.int64(0)

b*a возвращает 9.2233720368547758e+18, как вы видите, он представлен десятичными знаками в форме Эйлера.

type(b*a) возвращает np.float64

Следовательно, по вышеуказанной причине он преобразуется в float, то есть np.float(64). Форма Эйлера числа всегда требует плавающих/десятичных точек для ее представления

Причина рассмотрения b как np.int64(1): если он был np.int64(0), вы никогда не заметите результат, так как результатом будет все 0s

Ответ 2

Этот ответ на самом деле не является ответом: попытка попытаться лучше понять проблему!

С Python 2.7.13 я получил

In [24]: a = 9223372036854775808; type(a)
Out[24]: long

Пока в python 3.6.0 я получил

In [24]: a = 9223372036854775808; type(a)
Out[24]: int

И это согласуется с тем, что long по-прежнему называется int, даже если он ведет себя так же долго в Python3.

Может ли это быть частью проблемы сообщаемой ошибки? Если мы останемся на Python2, может ли то, что вы видели, быть ошибкой numpy в запросе типа значения, хранящегося в переменной при выполнении умножения? Рассмотрим

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

Число 9223372036854775808 хранится так долго.

В строке 15 процессор говорит: "Длинные времена int64 длинны, поскольку это самый большой контейнер".

Строка 16 процессор видит как int и говорит, что "int times np.int64 - это np.int64, поскольку я предпочитаю хранить его в виде numpy, поскольку вы его вызываете, но подождите... 9223372036854775808 не может оставаться в int64, поэтому я сейчас в беде (непредвиденная проблема, поскольку это не происходит при использовании только numpy-типа - строка 19). Затем я попал в" проблемный режим ", сохраняя результаты по умолчанию в самом большом контейнере с емкостью, который у меня есть, который является float64".

В Python3 строки 15 и 16 ведут себя по-разному: numpy всегда идет в "режиме тревоги", поскольку длинный тип всегда определяется как int:

In [10]: type(9223372036854775808 + np.int64(0))
Out[10]: numpy.float64

In [11]: type(a*b)
Out[11]: numpy.float64