Ошибка округления в Python с нечетным числом?

Я новичок в Python, и у меня есть один вопрос.
Почему округление числа вроде 5,5, 7,5 (любого).5 с нечетной целой частью с применением round(num) работает правильно (правило 5/4), но округление числа вроде (что угодно).5 с нечетной целой частью той же функцией возвращает только целую часть? (Но если мы добавим небольшое число, например 0,000000001, к этому десятичному числу, оно будет работать правильно)

Я имею в виду следующее:

round(9.5)

возвращает 10, и это правильно. Но

round(8.5)

возвращает 8, и это неправильно. И

round(8.5 + 0.0000000000001)

возвращает 9.

Почему это работает неправильно?
Я использую Python 3.2.2 в Windows.


person Ivan Akulov    schedule 10.04.2012    source источник
comment
Интересный. Python 2.7 возвращает 10.0 вместо round(9.5) и 9.0 вместо round(8.5).   -  person Tim Pietzcker    schedule 10.04.2012
comment
round(8.5) возвращает 9.0, как и ожидалось. У меня версия 2.7.2.   -  person Mike McMahon    schedule 10.04.2012


Ответы (1)


Python 3.x, в отличие от Python 2.x, использует банкировское округление для round() функция.

Это задокументированное поведение:

[I] Если два кратных одинаково близки, округление выполняется в сторону четного выбора (так, например, и округление (0,5), и округление (-0,5) равны 0, а округление (1,5) равно 2).

Поскольку числа с плавающей запятой по своей природе являются лишь приблизительными значениями, не должно иметь большого значения, как обрабатываются «точные» полуцелые числа — в любом случае в предыдущих вычислениях всегда могут быть ошибки округления.

Изменить: чтобы получить старое поведение округления, вы можете использовать

def my_round(x):
    return int(x + math.copysign(0.5, x))
person Sven Marnach    schedule 10.04.2012
comment
как раз собирался выложить эту жемчужину :) - person Mike McMahon; 10.04.2012
comment
Интересный. 2to3 справляется с этим? - person Mark Ransom; 10.04.2012
comment
@MarkRansom: Нет. Но я думаю, что если ваш код полагается на это, он все равно не работает. - person Sven Marnach; 10.04.2012
comment
И какую функцию я могу использовать для нормального округления, как в Python 2.7? - person Ivan Akulov; 10.04.2012
comment
@SvenMarnach, иногда речь идет не о том, чтобы полагаться на результаты, а скорее о прохождении тестов или о том, что ваши клиенты жалуются на изменения. - person Mark Ransom; 10.04.2012
comment
@gxoptg: попробуйте def roundHalfUp(f): return round(f + 0.00000000000001) или def roundHalfUp(f): return math.floor(f + 0.5) - person jedwards; 10.04.2012
comment
max(round(x), round(x + 1) - 1) дает неверные результаты для отрицательных чисел. - person agf; 10.04.2012
comment
Обобщая причину округления следующим образом: если x.5 чисел составляют значительную часть некоторых данных, округление их всех вверх также сдвигает среднее значение вверх. Но если вы округлите половину из них в большую сторону, а половину в меньшую, среднее значение должно остаться примерно таким же. - person Thomas K; 10.04.2012
comment
@MarkRansom: Нет, 2to3 не имеет дело с ошибками в Python 2, исправленными в Python 3. ;-) - person Lennart Regebro; 11.04.2012
comment
@jedwards: Как и в моей первой попытке, это решение не работает так же, как Python 2 round() для отрицательных чисел. - person Sven Marnach; 11.04.2012
comment
Поведение Python 3.9, кажется, различается в зависимости от того, округляете ли вы до целого числа или до десятичного числа; определенно какое-то неожиданное поведение здесь: round(1.05, 1) => 1.1 , round(1.15, 1) => 1.1 , но round(10.5) => 10, round(11.5) => 12 - person Oskar Austegard; 21.05.2021
comment
@OskarAustegard Это связано с природой чисел с плавающей запятой. Десятичное число 1,05 не может быть точно представлено в двоичном числе с плавающей запятой, поэтому оно округляется до ближайшего значения, которое может быть представлено, которое оказывается равным 1,05000000000000000444089209850062616169452667236328125. Поскольку это чуть больше 1,05, оно округляется. Точно так же 1,15 округляется до 1,149999999999999911182158029987476766109466552734375, когда десятичная строка преобразуется в число с плавающей запятой, поэтому она округляется в меньшую сторону. - person Sven Marnach; 21.05.2021
comment
Все это как-то спорно по этой причине. Подавляющее большинство десятичных чисел не могут быть точно представлены в виде двоичных чисел с плавающей запятой, поэтому мы всегда имеем дело с округленными числами. - person Sven Marnach; 21.05.2021
comment
Вот как можно увидеть, до чего округляются десятичные дроби: ideone.com/WR6FWU - person Sven Marnach; 21.05.2021