Проблема округления с Python
Но это должно быть 6.175. Если я раунд 6.1749999999999998 с 2 десятичными знаками, он правильно показывает 6.18. Поэтому я могу жить с этим.
Но если я вычислил это:
32.50 * 0.19 * 3 = 18.524999999999999
Это должно быть 18.525. Если я вокруг значения 18.524999999999999 с двумя десятичными знаками, оно показывает 18.52.
Это должно показать мне 18.53. Что я делаю неправильно и как я могу это исправить?
7 ответов
Если вам нужна точная арифметика, вы можете использовать десятичный модуль:
Короче говоря, вы не должны полагаться на точные значения чисел с плавающей точкой из-за того, как они хранятся в памяти.
См. также документы python об этом — Арифметика с плавающей точкой: проблемы и ограничения. Он содержит следующий отрывок:
Например, если вы попытаетесь округлить значение 2.675 до двух знаков после запятой, вы получите это
>>> round(2.675, 2)
2.67Документация для встроенной функции round() говорит, что она округляется до ближайшего значения, округляя галстуки от нуля. Поскольку десятичная дробь 2.675 находится на полпути между 2,67 и 2,68, вы может ожидать, что результат здесь будет (двоичное приближение к) 2.68. Его нет, потому что когда десятичная строка 2.675 преобразуется в двоичное число с плавающей запятой, оно снова заменяется двоичным аппроксимация, точное значение которого
2,67499999999999982236431605997495353221893310546875
Так как это приближение немного ближе к 2,67, чем к 2,68, его округленный вниз.
Python’s round() Function Doesn’t do What You Think
How to avoid this simple mistake with round() in Python 3
![]()
![]()
The Floating Point
I recently ran into a bug with my Python code that was the result of the last thing I would suspect: rounding. Here’s how to avoid making the same mistake.
The Problem
Basically, I expected the round() function to operate as rounding usually does, in that half numbers are rounded up to the next whole number. For example, round(4.5) should return 5 and round(5.5) should return 6 .
Surprisingly, that is not how rounding works in Python. Rounding half numbers does not round up, and in fact, it doesn’t always round down either. Instead, it rounds to the nearest even number.
This behavior is shown by the following:
It is worth pointing out that besides the half-number case, round() works as expected, in that it returns the nearest integer. For example, round(4.4) returns 4 and round(4.6) returns 5 .
Note: This is only the case with Python 3. round() in Python 2 behaves as you would usually expect.
The Solution
We can fix this by defining a new rounding function:
Extended Solution
We can also take this a little further. The round() function also has another argument called ndigits that specifies how many digits to round to. For example, we can call round(3.14159, 2) and get 3.14 .
However, we run into a similar issue with rounding half values. Consider the following for example:
To fix this, we can use a similar solution, and scale it to the specified number of decimal places with the following:
The if-statement is there so that we get an int rather than a float when rounding to 0 digits. This means that rather than normal_round(4.2) returning 4.0 it will return 4 .
Глюки округления в Python
Как вам такое "округление"?
Лично я в шоке. Что делать-то? Как в питоне нормально округлять?
$ python
Python 2.3.4 (#1, Sep 7 2004, 16:15:24)
[GCC 3.2.3 20030502 (Red Hat Linux 3.2.3-20)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> round(2.5899999999999999, 2)
2.5899999999999999
>>> round(2.58123, 2)
2.5800000000000001
>>> round(2.59123, 2)
2.5899999999999999
Re: Глюки округления в Python
Re: Глюки округления в Python
Ишшо один гений компьютерных вычислений.
Ну ка, напиши точное двоичное представление десятичного 0.1, а потом поразмышляй над этим.
Re: Re: Глюки округления в Python
> Подобное уже обсуждалось
Спасибо за ссылку, но малость не то. Я спрашиваю про функцию round(), вызвав которую, я указал точность два знака. Во-первых, получаем совсем другую точность, во-вторых, значение портится. Обратите внимание на результат:
>>> round(2.59123, 2)
2.5899999999999999
При имевшихся 2.59 получаем 2.58
Re: Re: Глюки округления в Python
> Ишшо один гений компьютерных вычислений.
(с благоговением в голосе) Сам то, поди, школу уже закончил?
> Ну ка, напиши точное двоичное представление десятичного 0.1, а потом поразмышляй над этим.
Ну ка, поразмышляй над этим:
Re: Re: Re: Глюки округления в Python
>Ну ка, поразмышляй над этим:
Зачем спрашивать, если ответов не собираешься слушать? Тебе дали _правильный_ ответ на твой вопрос. Предпочитаешь разжеваные ответы?
>’%2.2f’ % (2.5899999999999999)
Возьми справочник по командам процессора, найди там описание оператора "%", и поразмышляй над этим 🙂
Re: Re: Re: Re: Глюки округления в Python
> Тебе дали _правильный_ ответ на твой вопрос.
Где? :-O
> Возьми справочник по командам процессора, найди там описание оператора "%", и поразмышляй над этим 🙂
Смешная шутка.
Re: Re: Re: Re: Re: Глюки округления в Python
LX: Подобное уже обсуждалось.
watashiwa_daredeska пояснил: напиши точное. поразмышляй
Если нужно еще больше пояснений — вот: конечной длинны десятичные дроби редко представляются конечной длинны двоичными, процессора чаще всего работают именно с двоичными числами и почти никогда не бывают бесконечной разрядности. Следовательно лучшее приближение к числу 2.59, которое твой процессор может обеспечить — 2.5899999999999999, следующее (2.5900000000000003) в три раза "дальше".
А (‘%.2f’ %) — функция, возвращающая _десятичное_ представление, потому может работать правильно.
Re: Re: Re: Re: Re: Re: Глюки округления в Python
А теперь обратите внимание, что я не спрашивал, почему так происходит. Вы зря тратите своё время, рассказвая мне об этом, т.к. я и сам могу вам много чего рассказать. Если уж я не точно сформулировал вопрос, прошу прощения. Правильнее было спросить, "как увеличить точность вычислений?".
P.S. Индус Дерипаска, или как там его, со своим дерзким тоном идёт в пешее сексуальное путешествие.
Re: Re: Re: Re: Re: Re: Re: Глюки округления в Python
> обратите внимание, что я не спрашивал, почему так происходит.
Ну да, ты просто утверждал, что то, что происходит — неправильно. Тебе указали на обратное.
> зря тратите своё время
> я и сам могу вам много чего рассказать.
А вот это не похоже.
> Правильнее было спросить, "как увеличить точность вычислений?".
Это "несколько" отличается от первого поста, не находишь?
1. Хакнуть интерпретатор Python на предмет использования extended вместо double (насколько я понимаю, это в основном для i386 архитектуры).
2. Смотреть в сторону GMP: http://www.swox.com/gmp и http://gmpy.sourceforge.net (этот, правда, больше года не обновляется уже, но если чего не хватает, можешь и сам прикрутить).
3. Внимательно подумать, а оно тебе надо? Если важны только два знака после запятой, то мне сложно придумать задачу, для которой при этом не хватит точности double.
Re: Re: Re: Re: Re: Re: Re: Re: Глюки округления в Python
> Похоже на то
.
> А вот это не похоже.
.
> Это "несколько" отличается от первого поста, не находишь?
Как работает функция round в Python?
Функция Python round() очень полезна, когда мы хотим выполнить операцию округления.
Часто требуется быстро оценить значение, округлив или уменьшив длинные десятичные дроби с плавающей запятой. round() особенно полезен в этом случае.

Синтаксис функции Python round()
Функция очень простая. Он берет число и выводит желаемое округленное число.
Здесь нам нужно округлить num , поэтому мы передаем его в round() . Мы также можем указать точность округления с помощью ndigits . Это гарантирует, что число будет округлено с точностью до ndigits после десятичной точки.
Если вы хотите округлить его до целых значений, вам не нужно указывать это значение. В этом случае будет возвращено ближайшее целочисленное значение.
Кроме того, если число имеет форму x.5 , значения будут округлены в большую сторону, если округленное значение является четным числом. В противном случае оно будет округлено в меньшую сторону.
Например, 2,5 будет округлено до 2, поскольку 2 — ближайшее четное число, а 3,5 будет округлено до 4.
После этого давайте рассмотрим несколько примеров:
1 Целочисленное округление
В приведенном ниже фрагменте показано, как можно округлять числа до ближайшего целого.
2 Округление в четную сторону
Как упоминалось ранее, если и четная, и нечетная стороны одинаково близки к числу ( x.5 ), то округление произойдет с четной стороной.
3 Округление с помощью ndigit = None.
Если аргумент ndigit не указан (или None ), будет выполнено округление до ближайшего целого числа.
4 Округление с ndigit <0
Мы также можем передать отрицательное значение аргументу ndigit . Округление начнется слева от десятичной точки!
Итак, если у нашего исходного числа 3 цифры после десятичной точки, передача ndigit = -3 удалит эти 3 цифры перед десятичной точкой и заменит их на 0, что даст нам 0!
Аномалии при округлении чисел с плавающей запятой
Поскольку числа с плавающей запятой определяются их точностью, Python приближает эти числа во время вычислений. Из-за этих приближений их округление может иногда давать неожиданные результаты.
Рассмотрим блок ниже, результаты которого могут быть неожиданными:
Давайте посмотрим еще на несколько примеров:
Опять же, из-за приближения к плавающей запятой мы не получаем точного результата. В первом случае мы ожидали 21.58 , но получили только 21.57 .
Из-за этого всегда будьте осторожны при работе с числами с плавающей запятой, так как эти небольшие изменения вывода могут создать огромные проблемы.
Использование round() для настраиваемых объектов
Метод Python round() внутренне вызывает метод __round__() .
Мы можем переопределить этот метод, если создаем собственный класс. Следовательно, любой вызов round() для нашего объекта вместо этого перейдет к этому переопределяющему методу.
Как видите, мы смогли реализовать нашу собственную функцию округления для объекта MyClass .