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