Сумма помещается, произведение переполняется: dtype до умножения
Цена и количество выглядят нормально, общая сумма должна помещаться в int64. Но отдельные произведения уже испортились в int32. Указание широкого dtype только в sum не восстанавливает потерянное значение.
Следить за промежуточной операцией
Целые типы NumPy имеют фиксированный диапазон. Умножение двух массивов int32 обычно создаёт результат того же типа. Если произведение выходит за его пределы, значение переполняется до суммирования. Последующий перевод в int64 переносит уже неверное число.
Нужно расширить тип до умножения. Но int64 тоже имеет предел. Оцените максимально возможную цену, количество и число строк, включая возвраты и ошибочные крупные значения. Выбор dtype должен учитывать всю цепочку, а не только тип исходного файла.
Сравнить промежуточные результаты
В примере цена 50000 минимальных денежных единиц умножается на количество 50000. Произведение 2500000000 не помещается в знаковый int32, но помещается в int64. Для независимого контроля используем int Python, у которого нет такого фиксированного машинного предела.
Мы не полагаемся на конкретное отрицательное значение переполнения: проверяем несоответствие правильному результату. Это точнее выражает нарушение расчёта.
import numpy as np
price = np.array([50000, 2], dtype=np.int32)
qty = np.array([50000, 3], dtype=np.int32)
late = (price * qty).sum(dtype=np.int64)
line_value = price.astype(np.int64) * qty.astype(np.int64)
correct = line_value.sum(dtype=np.int64)
reference = sum(int(p) * int(q) for p, q in zip(price, qty))
print({"late_cast": int(late), "correct": int(correct), "line_dtype": str(line_value.dtype)})
assert int(correct) == reference == 2500000006
assert late != correct
assert np.iinfo(np.int32).max < 2500000000 < np.iinfo(np.int64).maxШирокая сумма неверных произведений остаётся неверной. Только расширение операндов до умножения даёт 2500000006. Контроль line_dtype показывает тип именно опасного промежуточного массива.
Проверить весь путь денег
Если деньги хранятся целыми копейками, арифметика сохраняет дискретность, пока значения помещаются в тип. Процентная скидка добавляет деление и правило округления. Переход к float ради увеличения диапазона способен изменить точность денежных единиц, поэтому это отдельное решение, а не универсальная замена int64.
Проверьте тип после чтения CSV, объединения и заполнения пропусков. Эти шаги могут поменять представление. В регулярной задаче удобно сохранять dtypes и допустимые диапазоны рядом с протоколом приёмки.
Контрольная сумма иногда тоже переполняется. Для небольшого проверочного набора считайте независимый результат Python int. Для большого потока используйте ограничение входов и оценку верхней границы либо подходящее точное представление.
Оставьте в контрольных данных значение прямо за пределом узкого типа. Обычные маленькие числа не обнаружат ошибку, даже если формула годами работает на них правильно. Увеличение бизнеса не должно впервые проверять диапазон вашего расчёта.
Закрепить на практике
В бесплатном уроке ndarray вы изучите dtype и свойства массива. После этой базы проверьте тип промежуточного произведения по примеру статьи, а не только тип итоговой суммы. Откройте бесплатный урок и задачи. Полная последовательность тем — в бесплатном курсе.
Продолжить на практике
- NumPy и pandas: практический тренажёр ↗
Бесплатный тренажёр NumPy и pandas для тех, кто знает основы Python. Научитесь очищать таблицы, объединять данные и собирать отчёты: 31 урок и 124 задачи с кодом и автоматической проверкой.
