Ещё один прикол в 3.12 — встроенная функция sum()
теперь использует специальный алгоритм для сложения чисел с плавающей точкой с минимальной потерей точности (прочитать про алгоритм можно на вики).
Раньше было как, складываешь 10 чиселок, где в результате ожидаешь получить 1, но получаешь что-то немного другое:
>>> sum([0.1] * 10)И ладно бы оно просто всегда ошибалось одинаково, дак ведь погрешность ещё и зависит от порядка, в котором складывать числа:
0.9999999999999999
>>> sum([0.1] * 5 + [0.05] * 10)А вы разве не знали, что сложение float'ов не коммутативно?
1.0000000000000004
>>> sum([0.05] * 10 + [0.1] * 5)
0.9999999999999999
>>> sum([0.1, 0.05, 0.05, 0.05, 0.05, 0.1, 0.1, 0.05, 0.05, 0.1, 0.05, 0.05, 0.05, 0.1, 0.05])
1.0000000000000002
Но была специальная функция
math.fsum()
, которая всё делает правильно:>>> math.fsum([0.1] * 10)Дак вот в 3.12 встроенная функция
1.0
>>> math.fsum([0.1] * 5 + [0.05] * 10)
1.0
>>> math.fsum([0.05] * 10 + [0.1] * 5)
1.0
sum()
даёт такие же результаты, как math.fsum()
. По крайней мере, я не смог найти примера, где они дали бы разный результат. Кроме того, по моим замерам, sum()
работает ещё и раза в полтора быстрее math.fsum()
:>>> timeit.timeit("sum([0.05] * 10 + [0.1] * 5)")Кто-нибудь понимает, зачем теперь нужна
0.26875441599986516
>>> timeit.timeit("math.fsum([0.05] * 10 + [0.1] * 5)", setup="import math")
0.34194887499961624
math.fsum()
?
>>Click here to continue<<
