Изменения в Python, встроенные в функцию round (), между 2,4 и 2,7 - PullRequest
4 голосов
/ 21 декабря 2011

Изменилась ли встроенная функция round () в Python между 2,4 и 2,7?

Python 2.4:

Python 2.4.6 (#1, Feb 12 2009, 14:52:44)
[GCC 3.4.6 20060404 (Red Hat 3.4.6-8)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> f = 1480.39499999999998181010596454143524169921875
>>> round(f,2)
1480.4000000000001
>>>

Python 2.7:

Python 2.7.1 (r271:86832, May 13 2011, 08:14:41)
[GCC 3.4.6 20060404 (Red Hat 3.4.6-11)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> f = 1480.39499999999998181010596454143524169921875
>>> round(f, 2)
1480.39
>>>

Есть ли способ вернуть поведение Python 2.4?

Я знаю, что правильным ответом, конечно, является использование десятичного арифметического модуля. К сожалению, это, вероятно, не вариант на данный момент, учитывая ограничения по времени.

Обновление

Для контекста я сравниваю значения в двух системах, одна из которых использует десятичное представление, а другая - с плавающей запятой. Это может (или не может) быть законным различием между системами, которые необходимо дополнительно проверить, поэтому я буду консультироваться с пользователями и иметь дело с этим на уровне «отчетности», а не в тот момент, когда я получаю данные из систем .

Спасибо за вашу помощь!

Ответы [ 3 ]

6 голосов
/ 21 декабря 2011

Ответ на ваш первый вопрос: да, round было исправлено в Python 2.7.

Ответ на ваш второй вопрос: я не уверен, если не считать фактического использования более раннего Python (2.6 все еще должен демонстрировать поведение 2.4). В данном конкретном случае ваша ценность неотличима от 1480,395 и 1480,395 (для нас, базовых 10 человек) раундов до 1480,40. Итак, я полагаю, вы могли бы сначала попытаться округлить в одно место сверх того, что вы действительно хотите, превратить это в строку, а затем получить десятичное число из этого ... но извините, я не могу думать ни о чем, кроме десятичного. Если я подумаю о чем-то (до того, как кто-то еще напишет что-нибудь получше), я вернусь и отредактирую.

(Но разве Десятичность так сложно использовать?)

Редактировать: Вот пример использования десятичного числа:

>>> from decimal import Decimal
>>> f = Decimal('1480.395')
>>> f.quantize(Decimal('0.00'))
Decimal('1480.40')
>>> float(Decimal('1480.40'))
1480.4

Некоторые заметки:

Python 2.7 позволяет использовать числа с плавающей запятой в качестве входных данных для десятичного числа. Не делайте этого , поскольку вы вернетесь туда, откуда начали. Кроме того, не используйте встроенную функцию round для десятичного числа, потому что эта функция преобразует ваше десятичное число обратно в число с плавающей точкой, и, таким образом, вы вернетесь туда, откуда начали. В своей простейшей форме десятичное число quantize принимает другое десятичное число, имеющее количество десятичных разрядов, которое вы действительно хотите (представьте его как шаблон для округления). Если ваши данные обязательно должны быть плавающими, то конвертируйте их обратно в плавающие только после выполнения всех ваших десятичных вычислений.

Наконец: я не уверен, что это покрывает все возможные странные случаи в поведении Python 2.4. Если вы полагаетесь на точно поведение Python 2.4, может не быть замены для работы на Python 2.4. То, что я описал выше, лишь на один шаг ближе к округлению в человеческом стиле.

3 голосов
/ 21 декабря 2011

Вероятно, нет, так как Python 2.4 фактически вернул неверный результат. Поскольку вы округляете сумму, которая строго меньше 5, правильный результат следует округлить в меньшую сторону.

Если вы сможете описать точное поведение, которое вам нужно, мы сможем создать альтернативный подход.

1 голос
/ 21 декабря 2011

На странице Что нового в Python 2.6 я вижу следующее (со ссылкой на PEP 3141 ):

Python 3.0 добавляет несколько абстрактных базклассы для числовых типов, вдохновленные числовой башней Схемы.Эти классы были перенесены в 2.6 в качестве модуля чисел.

...

В Python 3.0 PEP слегка переопределяет существующие встроенные функции round (), math.floor(), math.ceil () и добавляет новый, math.trunc (), который был перенесен в Python 2.6.math.trunc () округляет до нуля, возвращая ближайший интеграл, который находится между аргументом функции и нулем.

И, благодаря комментарию @ mark-dickinson, в что нового в python 2.7 страница, найден следующий текст:

Функция round () теперь также правильно округляется.

Так что да, изменения произошли в Python 2.7.Это можно проверить, проверив, что в python 2.6 поведение все еще старое:

Python 2.6.7 (r267:88850, Aug 11 2011, 12:18:09) 
[GCC 4.6.1] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> f = 1480.39499999999998181010596454143524169921875
>>> round(f, 2)
1480.4000000000001

В моем дистрибутиве linux у меня все еще есть доступ как к python 2.6, так и к python 2.7, и, вероятно, у вас есть и у вас;так что, если вам нужно старое поведение, возможно, вы можете попробовать запустить код в python 2.6.

...