Top.Mail.Ru
Ответы

1,7^2 = 2.8899999999999997 ? Или умножение в Python

Решила написать калькулятор квадратных уравнений в Python и, – вот незадача, при определенных расчетах и проверках понимаю, что что-то не так с умножением. Каким-то боком Python умножает 1.7 на 1.7 и получает число, указанное выше. В интернете не смогла найти адекватного ответа, но, поэкспериментировав, поняла, что это не единственная пара чисел с "подвохом".
2.3*2.3=5.289999999999999
И по какой-то сверхъестественной причине это вроде работает только с квадратами, ну или я просто не нашла других примеров в другом случае :'D.
Впринципе, это конечно приближенный ответ и можно было бы просто использовать round(*переменная*, 15), так как дальше по цепной реакции будут сокращаться девятки, но меня настораживает факт существования такого конфликта в пайтон, хоть и примерно понимаю его причину. (Возможно дело в системах счисления, но я бы хотела послушать людей, которые разбираются в этом)))

По дате
По Рейтингу
Аватар пользователя
Новичок

Используй Decimal в python(в интернете прочитай что это). А эта погрешность возникает из-за разных систем счислений. Кстати, вот реально годный канал https://www.youtube.com/watch?v=kG_ipMygRUc

Аватар пользователя
Искусственный Интеллект

Мадам, вы взяли число с 1 знаком после запятой и возвели его в квадрат. По всем правилам вы обязаны были после этого округлить полученное значение до 2 знаков после запятой, прежде чем выводить его. Почему вы этого не сделали?

Аватар пользователя
Просветленный

Числа float записываются в компьютерах неточно, если они не являются дробью двойки.
Числа в компе хранятся в двоичном виде, поэтому многие десятичные дроби превращаются в бесконечные периодические двоичные. Из-за чего какой-то кусочек приходится отбрасывать и получается неточность.

Попробуйте например это
>>> f'{1.7:.60f}'
'1.699999999999999955591079014993738383054733276367187500000000'
>>> f'{0.1:.60f}'
'0.100000000000000005551115123125782702118158340454101562500000'
Но
>>> f'{0.125:.60f}'
'0.125000000000000000000000000000000000000000000000000000000000'
потому, что 0.125 - это 1/8, а 8 - степень двойки.

Вот целый сайт сайт про это есть.
https://0.30000000000000004.com/

Аватар пользователя
Просветленный

Так это во всех ЯП. Зато на Пайтоне можно исхитряться по разному. Например, число вводить как дробь, а выводить как вещественное:
import fractions
x = fractions.Fraction(input('x = ?\b'))
print(float(x * x))
Тогда в случае введения х = 1.7 выдаст 2.89, а в случае х = 2.3 ответ будет 5.29.

Аватар пользователя
Искусственный Интеллект

Это не специфично для Python. Это проблема всех языков, использующих обычные дробные числа, как их воспринимает процессор. На одно дробное число отводится 4 или 8 байт, и закодировать дробную часть битами нередко выходит лишь в некотором приближении.

Число 1.7 хранится в памяти с погрешностью, которая не видна при выводе: программа показывает ограниченное число дробных знаков. Однако при умножении 1.7 на 1.7 вместе с числом умножается и его погрешность. Она вылезает на один знак вверх, ближе к точке, и становится видимой при выводе.

По этой причине есть смысл:
1) округлять числа после расчетов или перед выводом до необходимого вам количества знаков;
2) сравнивать дробные числа не через строгое равенство (a == b), а через модуль разницы между ними (abs(a - b) < delta, где delta — допустимая погрешность вроде 0.00001).

Для расчетов без погрешностей вы можете воспользоваться другим типом данных — decimal:
https://docs.python.org/3/library/decimal.html
Он может оказаться более медленным и менее удобным, но позволяет обеспечить точные расчеты и контролируемое округление.