Ошибка вычисления массива с использованием int dtype (не удается автоматически преобразовать dtype в 64-битную при необходимости) - PullRequest
3 голосов
/ 24 октября 2019

Я сталкиваюсь с проблемой неправильных вычислений с числами, когда входные данные для вычислений представляют собой массив чисел с 32-разрядным целочисленным типом данных, но выходные данные содержат большие числа, для которых требуется 64-разрядное представление.

Вот минимальный рабочий пример:

arr = np.ones(5, dtype=int) * (2**24 + 300)  # arr.dtype defaults to 'int32'

# Following comment from @hpaulj I changed the first line, which was originally:
# arr = np.zeros(5, dtype=int) 
# arr[:] = 2**24 + 300

single_value_calc = 2**8 * (2**24 + 300)
numpy_calc = 2**8 * arr

print(single_value_calc)
print(numpy_calc[0])

# RESULTS
4295044096
76800

Желаемым выводом является то, что массив numpy содержит правильное значение 4295044096, для представления которого требуется 64 бита. то есть я бы ожидал, что числовые массивы будут автоматически повышаться с int32 до int64, когда этого требуют выходные данные, скорее поддерживая 32-разрядный вывод и возвращаясь к 0 после превышения значения 2 ^ 32.

КонечноЯ могу решить проблему вручную, используя принудительное представление int64:

numpy_calc2 = 2**8 * arr.astype('int64')

, но это нежелательно для общего кода, поскольку в некоторых случаях для вывода требуется только 64-битное представление (т.е. для хранения больших чисел) ине все. В моём случае использования производительность критична, поэтому принудительное обновление в любой момент будет дорогостоящим.

Является ли это предполагаемым поведением массивов-пустышек? И если да, то есть ли чистое, эффективное решение, пожалуйста?

1 Ответ

2 голосов
/ 25 октября 2019

Кастинг и раскрутка шрифтов в numpy довольно сложны и иногда удивляют. Эта недавняя неофициальная статья Себастьяна Берга объясняет некоторые нюансы предмета (в основном концентрирующиеся на скалярах и 0d-массивах).

Цитата из этого документа:

Целые числа Python и числа с плавающей запятой

Обратите внимание, что целые числа Python обрабатываются точно так же, как и числовые. Они, однако, особенные в том, что у них нет dtype, ассоциированного с ними явно. Логика, основанная на значениях, как описано здесь, кажется полезной для целых чисел и чисел с плавающей точкой, чтобы разрешить:

arr = np.arange(10, dtype=np.int8)
arr += 1
# or:
res = arr + 1
res.dtype == np.int8

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

(выделение мое.)

См. Также Суть Аллана Холдейна, предполагающая принуждение в стиле C , ссылка на которую приведена в предыдущем документе:

В настоящее время, когда в двоичной операции участвуют два dtypes, принцип numpy заключается в том, что «диапазон выходного dtype охватывает диапазон обоих входных dtypes», , а когда задействован один dtype, никогда не происходит приведение.

(снова акцент мой.)

Так что я понимаю, что правила продвижения для бесчисленных скаляров и массивов различаются, в первую очередь потому, что невозможно проверить каждый элемент в массиве, чтобы определить,литье можно сделать безопасно. Снова из предыдущего документа:

Правила на основе скаляров

В отличие от массивов, где проверка всех значений невозможна, для скаляров (и 0-D массивов) проверяется значение.

Это будет означать, что вы можете использовать np.int64 с самого начала, чтобы быть безопасным (и если вы используете Linux, dtype=int фактически сделает это самостоятельно), или проверитьМаксимальное значение ваших массивов до подозрительных операций и определить, нужно ли вам продвигать dtype самостоятельно, в каждом конкретном случае. Я понимаю, что это может быть неосуществимо, если вы делаете много расчетов, но я не верю, что есть способ обойти это, учитывая текущие правила продвижения типа numpy.

...