Поведение округления Python 3.x
Я просто перечитывал Что нового в Python 3.0 и в нем говорится:
Изменена стратегия округления функции round() и тип возвращаемого значения. Точные половинные случаи теперь округлены до ближайшего четного результата от нуля. (Например, round (2.5) теперь возвращает 2, а не 3.)
и
документация для round:
Для встроенных типов, поддерживающих round(), значения округляются до ближайший кратный 10 к мощности минус n; если два кратных одинаково близко, округление выполняется по отношению к четному выбору
Итак, под v2.7.3:
In [85]: round(2.5)
Out[85]: 3.0
In [86]: round(3.5)
Out[86]: 4.0
как я и ожидал. Однако теперь под v3.2.3:
In [32]: round(2.5)
Out[32]: 2
In [33]: round(3.5)
Out[33]: 4
Это кажется противоречивым и противоречащим тому, что я понимаю о
округление (и связанное с поездкой людей). Английский не мой родной язык, но
пока я не прочитал это, я думал, что знаю, что такое округление: -/Я уверен
в момент введения v3 должно было быть некоторое обсуждение
это, но я не смог найти вескую причину в своем поиске.
- Кто-нибудь знает, почему это было изменено на это?
- Существуют ли какие-либо другие основные языки программирования (например, C, С++, Java, Perl,..), которые делают это (для меня непоследовательное) округление?
Что мне здесь не хватает?
UPDATE: @Li-aungYip comment re "Банкир округление" дал мне правильный поиск/ключевые слова для поиска, и я нашел этот вопрос SO: Почему .NET использует округление банкира как по умолчанию?, поэтому я буду внимательно его читать.
Ответы
Ответ 1
В наши дни Python 3.0 считается стандартным методом округления, хотя некоторые языковые реализации пока не работают.
Простая техника "всегда вокруг 0,5 вверх" приводит к небольшому смещению в сторону большего числа. При большом количестве вычислений это может быть значительным. Подход Python 3.0 устраняет эту проблему.
Существует более одного метода округления в общем использовании. IEEE 754, международный стандарт математики с плавающей точкой, определяет пять различных методов округления (по умолчанию используется Python 3.0). И есть другие.
Такое поведение не так широко известно, как должно быть. AppleScript был, если я правильно помню, одним из первых, кто применил этот метод округления. Команда round
в AppleScript действительно предлагает несколько опций, но по умолчанию используется округление к четному, как в IEEE 754. Очевидно, что инженеру, который реализовал команду round
надоели все запросы, чтобы "заставить ее работать так, как я" "В школе узнали", что он реализовал именно это: round 2.5 rounding as taught in school
является действительной командой AppleScript. :-)
Ответ 2
Вы можете управлять округлением, которое вы получаете в 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')
Ответ 3
Просто добавлю сюда важное примечание из документации:
https://docs.python.org/dev/library/functions.html#round
Заметка
Поведение 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)
Ответ 4
У меня недавно были проблемы с этим. Следовательно, я разработал модуль 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 в десятичном модуле (дополнительную информацию см. В документации модулей). Для нижеприведенных функций см. Документацию к документам или используйте 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 <[email protected]>
'''
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 <[email protected]>
'''
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
Ответ 5
Python 3.x округляет .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
Ответ 6
Поведение округления в Python 2 в Python 3.
Добавляем 1 на 15 десятичных знаков. Точность до 15 цифр.
round2=lambda x,y=None: round(x+1e-15,y)
Ответ 7
Некоторые случаи:
in: Decimal(75.29 / 2).quantize(Decimal('0.01'), rounding=ROUND_HALF_UP)
in: round(75.29 / 2, 2)
out: 37.65 GOOD
in: Decimal(85.55 / 2).quantize(Decimal('0.01'), rounding=ROUND_HALF_UP)
in: round(85.55 / 2, 2)
out: 42.77 BAD
Для исправления:
in: round(75.29 / 2 + 0.00001, 2)
out: 37.65 GOOD
in: round(85.55 / 2 + 0.00001, 2)
out: 42.78 GOOD
Если вы хотите больше десятичных знаков, например 4, вы должны добавить (+ 0,0000001).
Работа для меня.
Ответ 8
Образец репродукции:
['{} => {}'.format(x+0.5, round(x+0.5)) for x in range(10)]
['0.5 => 0', '1.5 => 2', '2.5 => 2', '3.5 => 4', '4.5 => 4', '5.5 => 6', '6.5 => 6', '7.5 => 8', '8.5 => 8', '9.5 => 10']
API: https://docs.python.org/3/library/functions.html#round
Состояния:
Возвращаемое число, округленное до точности ndigits после десятичной точки. Если ndigits опущен или равен None, он возвращает ближайшее целое число на свой вход.
Для встроенных типов, поддерживающих round(), значения округляются до ближайшего кратного 10 к степени минус ndigits; если два мультипликатора одинаково близки, округление выполняется до четного выбора (например, как раунд (0.5), так и раунд (-0.5) равны 0, а раунд (1.5) равен 2). Любое целочисленное значение допустимо для ndigits (положительное, нулевое или отрицательное). Возвращаемое значение является целым числом, если ndigits опущено или отсутствует. В противном случае возвращаемое значение имеет тот же тип, что и число.
Для общего номера объекта Python округлите делегатов до числа. круглый
Замечание Поведение round() для чисел с плавающей точкой может быть удивительным: например, round (2.675, 2) дает 2,67 вместо ожидаемых 2,68. Это не ошибка: это результат того факта, что большинство десятичных дробей не могут быть представлены именно как число с плавающей точкой. Посмотрите Арифметику с плавающей запятой: Проблемы и Ограничения для получения дополнительной информации.
Учитывая это понимание, вы можете использовать некоторую математику, чтобы решить ее
import math
def my_round(i):
f = math.floor(i)
return f if i - f < 0.5 else f+1
теперь вы можете запустить тот же тест с my_round вместо round.
['{} => {}'.format(x + 0.5, my_round(x+0.5)) for x in range(10)]
['0.5 => 1', '1.5 => 2', '2.5 => 3', '3.5 => 4', '4.5 => 5', '5.5 => 6', '6.5 => 7', '7.5 => 8', '8.5 => 9', '9.5 => 10']
Ответ 9
Круглый оператор округляет значение до ближайшего целого значения.
Например:
Если значение больше o.5, то оно округляется до 1
print(round(211.5554, 2)) // output is 211.56
Если значение меньше 0,5, оно округляется до 0
print(round(211.5544, 2)) // output is 211.55