[python] 파이썬 3.x 반올림 동작

방금 Python 3.0의 새로운 기능을 읽고 있었고 다음 과 같이 말합니다.

round () 함수 반올림 전략 및 리턴 유형이 변경되었습니다. 정확한 중간 사례는 이제 0이 아닌 가장 가까운 짝수로 반올림됩니다. 예를 들어 round (2.5)는 이제 3이 아니라 2를 반환합니다.

그리고 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

이것은 반 직관적이며 반올림에 대해 이해하는 것과 반대되는 것으로 보입니다 (그리고 사람들을 트립 할 수밖에 없습니다). 영어는 모국어가 아니지만이 글을 읽을 때까지 반올림의 의미를 알고 있다고 생각했습니다. 내 검색.

  1. 왜 이것이 이것이 변경되었는지에 대한 통찰력이 있습니까?
  2. 이러한 종류의 (일관되지 않은) 반올림을 수행 하는 다른 주류 프로그래밍 언어 (예 : C, C ++, Java, Perl, ..)가 있습니까?

내가 여기서 무엇을 놓치고 있습니까?

업데이트 : @ Li-aungYip의 “Banker ‘s rounding”에 대한 의견은 검색 할 올바른 검색어 / 키워드를 제공 했으며이 SO 질문을 발견했습니다 . 그래서 나는 그것을주의 깊게 읽을 것입니다.



답변

파이썬 3.0의 방식은 요즘 표준 반올림 방법으로 간주되지만 일부 언어 구현은 아직 버스에 없습니다.

간단한 “항상 반올림”기술은 더 높은 숫자를 향한 약간의 편견입니다. 많은 수의 계산을 사용하면 이것이 중요 할 수 있습니다. Python 3.0 접근 방식은이 문제를 해결합니다.

일반적으로 사용되는 반올림 방법은 여러 가지가 있습니다. 부동 소수점 수학에 대한 국제 표준 인 IEEE 754는 다섯 가지 다른 반올림 방법을 정의 합니다 (Python 3.0에서 사용하는 방법 이 기본값 임). 그리고 다른 것들도 있습니다.

이 동작은 예상만큼 널리 알려지지 않았습니다. 내가 올바르게 기억한다면, AppleScript는이 반올림 방법의 초기 채택 자였습니다. roundAppleScript 의 명령은 실제로 몇 가지 옵션을 제공하지만 IEEE 754와 마찬가지로 기본적으로 반올림입니다.이 round명령 을 구현 한 엔지니어 는 “내가 배운 것처럼 작동하도록 모든 요청에 부딪 쳤 습니다. “그것을 구현했습니다. round 2.5 rounding as taught in school유효한 AppleScript 명령입니다. 🙂


답변

Decimal 모듈을 사용하여 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

노트

float에 대한 round ()의 동작은 놀랍습니다. 예를 들어 round (2.675, 2)는 예상 2.68 대신 2.67을 제공합니다. 이것은 버그가 아닙니다. 대부분의 소수는 정확히 부동 소수점으로 표현할 수 없다는 사실의 결과입니다. 자세한 내용은 부동 소수점 산술 : 문제 및 제한 사항을 참조하십시오.

따라서 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)


답변

나는 최근에도 이것에 문제가 있었다. 따라서이 문제를 해결하고 동일한 반올림 동작을 제공하는 2 개의 함수 trueround () 및 trueround_precision ()을 가진 python 3 모듈을 개발했습니다 (은행가의 반올림이 아닌). 다음은 모듈입니다. 코드를 저장하고 복사하거나 가져 오기만하면됩니다. 참고 : trueround_precision 모듈은 ROUND_CEILING, ROUND_DOWN, ROUND_FLOOR, ROUND_HALF_DOWN, ROUND_HALF_EVEN, ROUND_HALF_UP, ROUND_UP 및 ROUND_05UP 플래그에 따라 필요에 따라 반올림 동작을 변경할 수 있습니다 (자세한 내용은 해당 모듈 설명서 참조). 아래 함수에 대해서는 docstring을 참조하거나 추가 문서를 위해 인터프리터에 복사 된 경우 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)

도움이 되었기를 바랍니다,

나르 니


답변

Python 3.x는 0.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

그러나 필요한 경우 십진수 반올림 “뒤로”를 항상 0.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


답변

Python 3의 Python 2 반올림 동작

소수점 이하 15 자리에 1을 더합니다. 최대 15 자리의 정확도.

round2=lambda x,y=None: round(x+1e-15,y)


답변

어떤 경우에는 :

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)을 추가해야합니다.

나를 위해 일하십시오.