2015-07-28 3 views
3

Я искал ошибки в программе, и я обнаружил, что он был произведен неожиданным поведением от Numpy ...Неожиданных Numpy/Py3k правила принуждения

При выполнении, например, простой арифметической операции на разном целочисленные типы, использующие Python3k и Numpy, как

(numpy.uint64) + (INT)

результат это ... numpy.float64

Вот пример:

v = numpy.array([10**16+1], dtype=numpy.uint64) 
print(v[0]) 
v[0] += 1 
print(v[0]) 

Он производит следующий результат:

10000000000000001 
10000000000000000 

который может быть весьма неожиданным, когда вы имеете дело с целыми числами, чтобы избежать ошибок округления ...

выше «проблема» легко может быть решена заменив 1 на numpy.uint64 (1), но я вижу много ошибок, исходящих из этого. Каковы правила и логика этой ситуации? Есть ли какая-либо документация о том, как в таком случае делаются принуждения? Я не мог найти его.

Раньше я думал, что вы могли бы иметь некоторое представление о принуждение с помощью .item(), но это еще больше вводит в заблуждение:

v = numpy.array([10**16+1], dtype=numpy.uint64) 
print(type(v[0].item())) 
v[0] = v[0].item() + 1 
print(v[0]) 

производит

<class 'int'> 
10000000000000001 
10000000000000002 

Так .item() преобразует numpy.uint64 в int, и если вы явно используете его в арифметической операции, он работает.

Я удивлен (но мне не хватает Numpy опыта, я думаю), что, когда 'а' соответствует Numpy конкретной DTYPE,

a.item() + 1 

и

a + 1 

не дают те же результаты ... и, таким образом, дают разные результаты при преобразовании обратно в numpy dtype.

(Используемая среда - это современное распределение Pyzo через IEP, если это имеет значение. Обычно я использую Python 2, но мне пришлось сделать пару тестов в Py3k, и это был удобный способ сделать . это)

+0

Он отлично работает с 'DTYPE = np.int64' вместо' DTYPE = np.uint64' (как для Python 2 и 3, 1,6 и NumPy 1,9). Я действительно не понимаю, почему это происходит, звучит как ошибка ... Просто используйте 'np.int64', нет причин использовать' uint64', переполненный на '2⁶⁴ - 1' или' 2⁶³ - 1' в значительной степени то же самое для всех практических целей. – rth

+1

Это интересно ... Действительно, это работает с 'dtype = np.int64' ... Не уверен, что это ошибка (хотя мне кажется, что это ошибка), так как« np.int32 + int »и' np .uint32 + int' оба преобразуются в 'np.int64', возможно, чтобы избежать переполнения. Почему 'np.int64 + int' становится' np.int64', а 'np.uint64 + int' становится' np.float64' все еще ускользает от меня. У меня много обходных решений, но я хотел бы знать, есть ли причина для этого, и где я могу это найти. Спасибо за комментарий ... – Koren

+0

Вот соответствующая [проблема с numpy] (https://github.com/numpy/numpy/issues/5745), которая делает чувство на каком-то уровне, хотя оно все еще не очень интуитивное. – rth

ответ

0

Как было отмечено выше:

отлично работает с:

dtype=np.int64 

вместо:

dtype=np.uint64 

как для python 2, так и 3, numpy 1.6 и 1.9.

Просто используйте:

np.int64 

нет никаких оснований для использования uint64, переполненные в 2⁶⁴ - 1 или 2⁶³ - 1 довольно много то же самое для всех практических целей.

Список литературы

+0

Я категорически не согласен, что это одно и то же для всех практических целей ... Мне часто нужны точные целочисленные типы при работе с двоичными данными. Вопрос старый, но я думаю, что мне это нужно в то время (я окончательно использовал его до и после). С помощью int64 у вас будут проблемы с сопоставлением и предупреждение о переполнении. Это, как говорится, просто неожиданный неявный выбор конверсии, и его легко обойти, поэтому это не проблема, но я думаю, что это должно быть более очевидным в документации numpy. Не то, чтобы не было случаев, когда документация numpy далека от совершенства: / – Koren

Смежные вопросы