Python 3.х округления поведения
Я просто перечитываю Что нового в Python 3.0 и в нем говорится:
стратегия округления функции round () и тип возвращаемого значения изменились. Точные случаи на полпути теперь округляются до ближайшего четного результата вместо этого далеко от нуля. (Например, round (2.5) теперь возвращает 2, а не 3.)
и документация для круглые:
для встроенных типов, поддерживающих round (), значения являются округленное до ближайшего кратного 10 в степени минус N; если два кратных одинаково близко, округление делается в сторону четного выбора
Итак, под П2.7.3:
In [85]: round(2.5)
Out[85]: 3.0
In [86]: round(3.5)
Out[86]: 4.0
Как я и ожидал. Однако теперь под В3.2.3:
In [32]: round(2.5)
Out[32]: 2
In [33]: round(3.5)
Out[33]: 4
Это кажется нелогичным и противоречит тому, что я понимаю о округление (и обязательно споткнуться людей). Английский не мой родной язык, но пока я не прочитал это, я думал, что я знал, что означает округление: - / я уверен в то время, когда v3 был представлен, должно быть, было некоторое обсуждение это, но я не смог найти хорошую причину в моем поиске.
- кто-нибудь имеет представление о том, почему это было изменено на это?
- существуют ли другие основные языки программирования (например,C, C++, Java, Perl, ..) что делают такого рода (мне непоследовательные) округления?
чего мне не хватает здесь?
обновление: комментарий @Li-aungYip re "округление банкира" дал мне правильный поисковый запрос / ключевые слова для поиска, и я нашел этот вопрос:почему .NET использует округление банкира по умолчанию?, так что я буду читать это внимательно.
6 ответов:
путь Python 3.0 считается стандартным методом округления в эти дни, хотя некоторые языковые реализации еще не находятся на шине.
простой метод "всегда округляет 0,5 вверх" приводит к небольшому смещению в сторону более высокого числа. При большом количестве вычислений это может быть значительным. Подход Python 3.0 устраняет эту проблему.
существует более одного метода округления в общем использовании. IEEE 754, международный стандарт для математики с плавающей запятой, определяет пять различных методов округления (по умолчанию используется Python 3.0). А есть и другие.
это поведение не так широко известно, как должно быть. AppleScript был, если я правильно помню, ранним последователем этого метода округления. Элемент
round
команда в AppleScript на самом деле предлагает несколько вариантов, но round-towards-even является значением по умолчанию, как и в IEEE 754. По-видимому, инженер, который реализовалround
команда так надоела всем просьбы "заставить его работать так, как я узнал в школе", что он реализовал именно это:round 2.5 rounding as taught in school
является допустимой командой AppleScript. : -)
вы можете контролировать округление вы получаете в Py3000 с помощью модуль десятичных:
>>> decimal.Decimal('3.5').quantize(decimal.Decimal('1'), rounding=decimal.ROUND_HALF_UP) >>> Decimal('4') >>> decimal.Decimal('2.5').quantize(decimal.Decimal('1'), rounding=decimal.ROUND_HALF_EVEN) >>> Decimal('2') >>> decimal.Decimal('3.5').quantize(decimal.Decimal('1'), rounding=decimal.ROUND_HALF_DOWN) >>> Decimal('3')
просто добавьте сюда важное примечание из документации:
https://docs.python.org/dev/library/functions.html#round
Примечание
поведение round() для поплавков может быть удивительным: например, раунд (2.675, 2) дает 2.67 вместо ожидаемых 2.68. Это не ошибка: это результат того, что большинство десятичных дробей не может быть представлен точно как поплавок. См. Раздел Арифметика С Плавающей Запятой: Проблемы и Ограничения для получения дополнительной информации.
Так что не удивляйтесь, чтобы получить следующие результаты в Python 3.2:
>>> round(0.25,1), round(0.35,1), round(0.45,1), round(0.55,1) (0.2, 0.3, 0.5, 0.6) >>> round(0.025,2), round(0.035,2), round(0.045,2), round(0.055,2) (0.03, 0.04, 0.04, 0.06)
У меня недавно тоже были проблемы с этим. Следовательно, я разработал модуль python 3, который имеет 2 функции trueround() и trueround_precision (), которые обращаются к этому и дают такое же поведение округления, которое используется в начальной школе (не округление банкира). Вот этот модуль. Просто сохраните код и скопируйте его или импортируйте. Примечание: модуль trueround_precision может изменять поведение округления в зависимости от потребностей в соответствии с ROUND_CEILING, ROUND_DOWN, ROUND_FLOOR, Флаги ROUND_HALF_DOWN, ROUND_HALF_EVEN, ROUND_HALF_UP, ROUND_UP и ROUND_05UP в десятичном модуле (дополнительную информацию см. В документации по этим модулям). Для функций ниже см. docstrings или используйте help(trueround) и help (trueround_precision), если они скопированы в интерпретатор для дальнейшей документации.
#! /usr/bin/env python3 # -*- coding: utf-8 -*- def trueround(number, places=0): ''' trueround(number, places) example: >>> trueround(2.55, 1) == 2.6 True uses standard functions with no import to give "normal" behavior to rounding so that trueround(2.5) == 3, trueround(3.5) == 4, trueround(4.5) == 5, etc. Use with caution, however. This still has the same problem with floating point math. The return object will be type int if places=0 or a float if places=>1. number is the floating point number needed rounding places is the number of decimal places to round to with '0' as the default which will actually return our interger. Otherwise, a floating point will be returned to the given decimal place. Note: Use trueround_precision() if true precision with floats is needed GPL 2.0 copywrite by Narnie Harshoe <signupnarnie@gmail.com> ''' place = 10**(places) rounded = (int(number*place + 0.5if number>=0 else -0.5))/place if rounded == int(rounded): rounded = int(rounded) return rounded def trueround_precision(number, places=0, rounding=None): ''' trueround_precision(number, places, rounding=ROUND_HALF_UP) Uses true precision for floating numbers using the 'decimal' module in python and assumes the module has already been imported before calling this function. The return object is of type Decimal. All rounding options are available from the decimal module including ROUND_CEILING, ROUND_DOWN, ROUND_FLOOR, ROUND_HALF_DOWN, ROUND_HALF_EVEN, ROUND_HALF_UP, ROUND_UP, and ROUND_05UP. examples: >>> trueround(2.5, 0) == Decimal('3') True >>> trueround(2.5, 0, ROUND_DOWN) == Decimal('2') True number is a floating point number or a string type containing a number on on which to be acted. places is the number of decimal places to round to with '0' as the default. Note: if type float is passed as the first argument to the function, it will first be converted to a str type for correct rounding. GPL 2.0 copywrite by Narnie Harshoe <signupnarnie@gmail.com> ''' from decimal import Decimal as dec from decimal import ROUND_HALF_UP from decimal import ROUND_CEILING from decimal import ROUND_DOWN from decimal import ROUND_FLOOR from decimal import ROUND_HALF_DOWN from decimal import ROUND_HALF_EVEN from decimal import ROUND_UP from decimal import ROUND_05UP if type(number) == type(float()): number = str(number) if rounding == None: rounding = ROUND_HALF_UP place = '1.' for i in range(places): place = ''.join([place, '0']) return dec(number).quantize(dec(place), rounding=rounding)
надеюсь, это поможет,
Narnie
поведение округления Python 2 в python 3.
добавление 1 в 15 десятичных знаков. Точность до 15 цифр.
round2=lambda x,y=None: round(x+1e-15,y)
Python 3.х раундов .5 значения для соседа, который даже
assert round(0.5) == 0 assert round(1.5) == 2 assert round(2.5) == 2 import decimal assert decimal.Decimal('0.5').to_integral_value() == 0 assert decimal.Decimal('1.5').to_integral_value() == 2 assert decimal.Decimal('2.5').to_integral_value() == 2
однако можно изменить десятичное округление "назад" на всегда круглое .5-при необходимости :
decimal.getcontext().rounding = decimal.ROUND_HALF_UP assert decimal.Decimal('0.5').to_integral_value() == 1 assert decimal.Decimal('1.5').to_integral_value() == 2 assert decimal.Decimal('2.5').to_integral_value() == 3 i = int(decimal.Decimal('2.5').to_integral_value()) # to get an int assert i == 3 assert type(i) is int