Обратите внимание на следующий код: создание массива numpy и вызов встроенной функции Python sum
дает результаты, отличные от numpy.sum
Как реализована функция суммы numpy? И почему результат другой?
test = [.1]*10
test = [np.float64(x) for x in test]
test[5]= np.float64(-.9)
d = [np.asarray(test) for x in range(0,60000)]
sum(sum(d))
результаты
np.float64(-1.7473212210461497e-08)
но
np.sum(d)
результаты
np.float64(9.987344284922983e-12)
np.sum(np.sum(d, axis=0))
даст тот же результат, что и sum(sum(d))
, с небольшой погрешностью, так что это просто скучная неточность оси/поплавка.
@wim Они дают более похожий, но не тот же результат.
Этот вопрос похож на: Не работает ли математика с плавающей запятой?. Если вы считаете, что это другое, отредактируйте вопрос, поясните, чем он отличается и/или как ответы на этот вопрос не помогают решить вашу проблему.
Судя по первому комментарию, если вы удивлены, что результаты разные, вы, вероятно, также должны быть удивлены, что ни один из них не равен 0?
Это связано с порядком суммирования. Если вы сначала сложите все 0,1, вы получите большой промежуточный результат, что приведет к более высокой неточности конечного результата. Если вы идете по строкам (9x 0,1, 1x -0,9), промежуточный результат остается ближе к 0, сохраняя точность до конца. (редактировать -... опубликовано как ответ..)
Не дурак, имхо; другой вопрос объясняет, почему результат неточен, но не объясняет, почему есть два разных результата (по-видимому) одной и той же операции.
Другая ошибка заключается в том, что сумма Python — это сумма сокращения, а сумма numpy — это попарная сумма. Попробуйте sum([np.float64(1)] + [np.float64(1e-16)]*10)
.
Посмотрите math.fsum
, docs.python.org/3/library/math.html
@ Liam385 Liam385 Хорошо, похоже. Дело в том, сколько вопросов и ответов нам нужно на этом сайте о неточностях с плавающей запятой, это не очень интересно.
Все повторяющиеся вопросы скучны. Все неповторяющиеся вопросы интересны. Людям следует стараться избегать повторения вопросов. Но если есть тема, которая вам скучна, именно вам следует ее избегать.
Вопрос не обязательно в неточности ФП, мы все это понимаем. Речь идет о нулевой реализации суммирования. У @ken был ответ, который я искал, кажется, что numpy использует попарное суммирование, с которым я не был знаком
Мы хотим, чтобы ответы находились в специальном месте «ответ». Наличие ответа внутри вопроса сбивает с толку; мы здесь этого не делаем. Я удалил его; см. ниже, если вам нужны ответы.
Это связано с порядком суммирования. Если вы сначала сложите все 0,1, вы получите большой промежуточный результат, что приведет к более высокой неточности конечного результата. Если вы идете по строкам (9x 0,1, 1x -0,9), промежуточный результат остается ближе к 0, сохраняя точность до конца.
Еще варианты:
>>> np.sum(np.sum(arr, axis=0)) # column-wise iteration
-1.747685018926859e-08
>>> np.sum(np.sum(arr, axis=1)) # row-wise iteration, more accurate
-3.3306690738754696e-12
>>> np.sum(arr)
9.987344284922983e-12
>>> sum(sum(arr))
-1.7473212210461497e-08
Еще немного теории:
Почему np.sum(np.sum(arr, axis=0)) и sum(sum(arr)) не дают одинаковый результат? Разве они не складывают по одним и тем же осям и в том же порядке? Вопрос снова в том, почему эти вызовы функций, которые логически должны быть одинаковыми, дают разные результаты.
Хороший вопрос. Возможно, numpy использует дополнительные трюки (см. другой ответ) вместо того, чтобы перебирать числа один за другим.
вот фактическое суммирование numpy, если вам интересно. github.com/numpy/numpy/blob/main/numpy/_core/src/umath/…
Numpy использует попарное суммирование:https://github.com/numpy/numpy/pull/3685 но Python использует суммирование с сокращением.
Ответ лишь частично связан с неточностью FP, потому что, если у меня есть массив чисел FP и я использую один и тот же алгоритм для их суммирования, я должен ожидать того же результата, если суммирую их в одном и том же порядке.
дурак? Математика с плавающей запятой не работает?