Я выполняю некоторые векторизованные вычисления, используя numpy. Я исследовал ошибку, которая у меня возникла, и я закончил этой строкой:
(vertices[:,:,:,0]+vertices[:,:,:,1]*256)*4
Ожидалось, что результат будет 100728 для индекса vertices[0,0,17], однако я получаю 35192.
Когда я попытался изменить его на 4.0 вместо 4, я получил правильное значение 100728 и, таким образом, исправил свою ошибку.
Я хотел бы понять, почему здесь важна плавающая запятая, особенно потому, что я использую python 3.7, и это умножение, а не деление.
Дополнительная информация:
vertices.shape=(203759, 12, 32, 3)
python==3.7
numpy==1.16.1
Редактировать 1:
Кроме того, если бы вы могли предоставить некоторые образцы данных, где это не удается, это было бы полезно. Какие значения в vertices[0,0,17]?
тип вершин "numpy.uint8"
вершины [0, 0, 17] равны [94, 98, 63]
как подсказка: 100728% 2^16 = 35192
@Kasparov92, что ты имеешь ввиду под vertices[0, 0, 17] => [94, 98, 63] ?
@Aaron дал вам решение: попробуйте изменить тип на uint16 или uint32.
Я использовал «4.0», и меня это устраивает, я искал объяснение, и @Aaron заставил меня добраться до момента ахааа :D






Проблема здесь в том, что вы используете слишком маленькие целые числа, и число переполняется и переносится, потому что numpy использует целые числа фиксированной ширины, а не бесконечную точность, как у python int. Numpy будет "продвигать" типом результата на основе входных данных, но не будет продвигать результат в зависимости от того, произошло ли переполнение или нет (это делается до фактического вычисления.
В этом случае, когда вы умножаете: vertices[:,:,:,1]*256 (я буду называть это A), 256 не может содержаться в uint8, поэтому он переходит к следующему более высокому типу: uint16 это позволяет результату умножения содержать правильное значение в этом случае, потому что максимально возможное значение любого элемента в verticies равно 255, поэтому максимально возможное значение равно 255 * 256, что отлично подходит для 16-битного uint.
Затем вы добавляете vertices[:,:,:,0] + A (я буду называть это B). если наибольшее значение A было 255 * 256, а наибольшее значение vertices[:,:,:,0] равно 255 (опять же наибольшее значение uint8), наибольшая сумма двух равна 216-1 (наибольшее значение, которое вы можете хранить в 16-битное целое число без знака). Это все еще хорошо, пока вы не перейдете к последнему умножению.
Когда вы доберетесь до B * 4, numpy снова должен решить, каким должен быть тип возвращаемого значения. Целое число 4 легко помещается в uint16, поэтому numpy не продвигает тип еще выше до uint32 или uint64, потому что он не предотвращает упреждающее переполнение, как описано ранее. Это приводит к тому, что любые произведения умножения, превышающие 216-1, возвращаются по модулю 216.
Если вместо этого вы используете число с плавающей запятой (4. or 4.0), numpy рассматривает это как «более высокий» тип значения, который не может поместиться внутри uint16, поэтому он переводит результат в число с плавающей запятой, которое может вмещать гораздо более высокие числа без переполнения.
Если вы не хотите менять весь массив: verticies на больший dtype, вы можете просто взять результат B и преобразовать его, прежде чем умножать на 4 как таковой: B.astype(np.uint64) * 4. Это позволит вам хранить большие значения много без переполнения (хотя на самом деле это не устраняет проблему, если значение больше 4).
ссылка, на которую вы указали, говорит: «Когда используются как скаляры, так и массивы, тип массива имеет приоритет». Разве это не означает, что в (A * 256)uint8 из A будет иметь приоритет над uint16 скаляра 256? Не уверен, что здесь означает «имеет приоритет».
Спасибо за подробное объяснение. Я ценю ваше время, объясняя и указывая на причины (Y)
@fountainhead Я думаю, они имеют в виду, что имеют приоритет в том, как они определяют int, float или другое. В примере показана ситуация, когда число с плавающей запятой может быть приведено к типу int, если это можно сделать точно, что подчеркивает отличие от правил приведения типов c/c++. Это определенно можно было бы объяснить немного яснее.
Каков тип значений в вершинах?