Округление с плавающей точкой с ошибкой представления до ближайшего и правильного результата
У меня возникла ситуация, когда классическая ошибка представления в Python стала проблемой: мне нужно, чтобы они использовались для операций с матрицами в Numpy, а десятичный тип еще не поддерживается.
Вы все знаете, что если я сделаю 111.85 * 111.85
я получу 12510.422499999999
но если я round(12510.422499999999, 4)
Я могу получить правильный результат, который, конечно, 12510.4225
,
Но актуальные вопросы:
- Этот раунд - хорошая идея и хорошая практика?
- Будет ли это работать для всех случаев? иногда позиция десятичных дробей, где десятичные знаки..999 могут быть больше
- И, наконец, как получить соответствующее количество десятичных позиций для использования с раундом для всех возможных значений?
2 ответа
Даже если вы округлите число, десятичное число все равно будет не таким , как вы ожидаете. Python может отображать только самые значимые биты, но основная десятичная погрешность все еще там.
Документы по Python посвящают этому раздел
Многие пользователи не знают о приближении из-за способа отображения значений. Python печатает только десятичное приближение к истинному десятичному значению двоичного приближения, хранящегося на машине. На большинстве машин, если бы Python должен был печатать истинное десятичное значение двоичного приближения, сохраненного для 0.1, он должен был бы отображать
>>> 0.1 0.1000000000000000055511151231257827021181583404541015625
Это больше цифр, чем большинство людей считают полезным, поэтому Python сохраняет количество цифр управляемым, отображая вместо этого округленное значение
>>> 1 / 10 0.1
В большинстве случаев неточность можно смело игнорировать. Если вы имеете дело с очень маленькими или очень большими числами или вам нужна точность во многих десятичных разрядах, вы можете использовать десятичную библиотеку
>>> Decimal('111.85') * Decimal('111.85')
Decimal('12510.4225')
Реальная проблема здесь состоит в том, чтобы идентифицировать, как ошибка представления могла начать быть проблемой во-первых.
Вы не должны использовать представление для удобочитаемой печати поплавков, вы должны использовать, например, str.format
или какой-то другой метод представления.
Сохраняйте свои числа в качестве чисел для всех вычислений (независимо от того, делаете ли вы это с помощью чисел с плавающей запятой или десятичных дробей или чего-то еще...) и только округляйте или усекайте вещи при представлении.