round ()가 제대로 반올림되지 않는 것 같습니다.


123

round () 함수에 대한 문서 는 숫자를 전달하고 소수점 이하 자리를 반올림하도록 지정합니다. 따라서 다음 수행해야합니다.

n = 5.59
round(n, 1) # 5.6

그러나 실제로는 오래된 부동 소수점 기이함이 들어와 다음과 같은 결과를 얻습니다.

5.5999999999999996

UI를 위해 5.6. 나는 인터넷을 샅샅이 뒤져서 이것이 파이썬 구현에 의존한다는 몇 가지 문서 를 발견했습니다 . 불행히도 이것은 내 Windows dev 컴퓨터와 내가 시도한 각 Linux 서버에서 발생합니다. 여기도 참조하십시오 .

내 라운드 라이브러리를 만드는 데 부족한데,이 문제를 해결할 방법이 있습니까?


4
나는 파이썬 2.7.11 라운드 (5.59)로 이것을 시도했고 윈도우와 리눅스 x86 64 비트 머신 모두에서 5.6으로 결과를주고있다. Cython? (언급 된 문서 링크는 지금 변경된 것 같다)
Alex Punnen

2
실제로 제대로 작동하지 않는 곳은 round(5.55, 1) = 5.5.
Dmitry

답변:


101

저장 방식을 도울 수는 없지만 최소한 서식이 올바르게 작동합니다.

'%.1f' % round(n, 1) # Gives you '5.6'

11
난 노력 print '%.2f' % 655.665하지만 반환 655.66이 있어야655.67
리자

1
@Kyrie는 stackoverflow.com/questions/9301690/…를 참조하십시오 . 여기서는 부동 소수점 부정확성이 원인입니다. "5.665-> 5.67"이지만 "15.665-> 15.66"입니다. 정확한 정밀도가 필요한 경우 소수를 사용하십시오.
Jimmy

7
이것은 검색 후에 작동합니다 :) from decimal import Decimal, ROUND_HALF_UP, ROUND_HALF_DOWN# 부동 숫자 반올림에 사용 # 부동 소수점의 Decimal(str(655.665)).quantize(Decimal('1.11'), rounding=ROUND_HALF_UP)문제점 및 한계
Liza

102

반올림하지 않아도 서식이 올바르게 작동합니다.

"%.1f" % n

18
문서 에 따르면 이 스타일의 문자열 형식은 결국 사라질 것입니다. 형식이 될 새로운 스타일"{:.1f}".format(n)
whereswalden

2
라운드 제대로되지 않습니다 '%.5f' % 0.988625제공0.98862
schlamar

@schlamar : round ()의 동작이기도합니다 : round (0.988625,5)도 0.98862를 제공합니다. 라운드 (0.988626,5)주고 잘 0.988626 0.98863 % ".5f %"로
Vinko Vrsalovic

불행히도 "% .2f"% 2.675는 2.67을 반환합니다.이 방법을 사용하고 2.68
Dion

30

Decimal 모듈을 사용하는 경우 'round'기능을 사용하지 않고도 근사값을 계산할 수 있습니다. 특히 통화 응용 프로그램을 작성할 때 반올림에 사용했던 내용은 다음과 같습니다.

Decimal(str(16.2)).quantize(Decimal('.01'), rounding=ROUND_UP)

16.20 인 10 진수를 반환합니다.


4
이것이 바로 정확한 답입니다 . 정확성이 중요한 곳은 거의 모든 곳에 있습니다. 물론입니다. 약간 장황 합니다. 그러나 도우미 함수에 그 빠는 것을 던져 넣으면 형식을 지정하고 이동하는 것이 좋습니다.
Cecil Curry

2
rounding='ROUND_UP'
LMc

이 오류가 발생 NameError: global name 'ROUND_UP' is not defined하면 반올림 함수를 가져와야합니다 from decimal import Decimal, ROUND_UP.. 다른 반올림 기능
스티븐 블레어

귀하의 예제는 여전히 위험 해 보입니다. str ()에서 제공하는 반올림에 의존합니다.
YvesgereY

21

round(5.59, 1)잘 작동합니다. 문제는 5.6이 이진 부동 소수점으로 정확하게 표현 될 수 없다는 것입니다.

>>> 5.6
5.5999999999999996
>>> 

Vinko가 말했듯이 문자열 형식을 사용하여 표시를 위해 반올림 할 수 있습니다.

파이썬에는 필요한 경우 십진 산술을위한 모듈 이 있습니다.


1
이것은 더 이상 Python 2.7 또는 Python 3.5에서 문제가되지 않습니다
vy32


10

데이터 유형을 정수로 전환 할 수 있습니다.

>>> n = 5.59
>>> int(n * 10) / 10.0
5.5
>>> int(n * 10 + 0.5)
56

그런 다음 로케일의 소수 구분 기호를 삽입하여 숫자를 표시하십시오.

그러나 Jimmy의 대답 이 더 좋습니다.


5

부동 소수점 수학은 사소하지만 성가신 정밀도 부정확성에 취약합니다. 정수 또는 고정 소수점으로 작업 할 수 있으면 정밀도가 보장됩니다.


5

Decimal 모듈 살펴보기

Decimal은 "사람들을 염두에두고 설계된 부동 소수점 모델을 기반으로하며 반드시 가장 중요한 지침 원칙을 가지고 있습니다. 컴퓨터는 사람들이 학교에서 배우는 산술과 동일한 방식으로 작동하는 산술을 제공해야합니다." – 십진 산술 사양에서 발췌.

십진수는 정확하게 표현할 수 있습니다. 반대로 1.1 및 2.2와 같은 숫자는 이진 부동 소수점으로 정확하게 표현되지 않습니다. 최종 사용자는 일반적으로 1.1 + 2.2가 이진 부동 소수점 에서처럼 3.3000000000000003으로 표시 될 것으로 기대하지 않습니다.

Decimal은 부동 소수점 연산 필요로하는 앱을 쉽게 작성하고 그 결과를 사람이 읽을 수있는 형식 (예 : 회계)으로 표시해야하는 작업 유형을 제공합니다 .



4

참으로 큰 문제입니다. 이 코드를 사용해보십시오.

print "%.2f" % (round((2*4.4+3*5.6+3*4.4)/8,2),)

4.85를 표시합니다. 그런 다음 다음을 수행합니다.

print "Media = %.1f" % (round((2*4.4+3*5.6+3*4.4)/8,1),)

4.8을 보여줍니다. 손으로 계산합니까 정확한 답은 4.85이지만 시도해 보면 다음과 같습니다.

print "Media = %.20f" % (round((2*4.4+3*5.6+3*4.4)/8,20),)

진실을 볼 수 있습니다. 부동 소수점은 분모가 2의 거듭 제곱 인 분수의 가장 가까운 유한 합으로 저장됩니다.


3

%sprintf와 유사한 문자열 형식 연산자를 사용할 수 있습니다 .

mystring = "%.2f" % 5.5999


2

내가 뭐하는 거지:

int(round( x , 0))

이 경우 먼저 단위 수준에서 적절하게 반올림 한 다음 부동 소수점 인쇄를 피하기 위해 정수로 변환합니다.

그래서

>>> int(round(5.59,0))
6

나는이 대답이 문자열 형식을 지정하는 것보다 더 잘 작동한다고 생각하며 round 함수를 사용하는 것이 더 감각적입니다.


2

round()이 경우에는 전혀 의존하지 않을 것 입니다. 치다

print(round(61.295, 2))
print(round(1.295, 2))

출력됩니다

61.3
1.29

가장 가까운 정수로 반올림해야하는 경우 원하는 출력이 아닙니다. 이 동작을 우회하려면 math.ceil()(또는 math.floor()반올림하려는 경우) :

from math import ceil
decimal_count = 2
print(ceil(61.295 * 10 ** decimal_count) / 10 ** decimal_count)
print(ceil(1.295 * 10 ** decimal_count) / 10 ** decimal_count)

출력

61.3
1.3

도움이되기를 바랍니다.


1

암호:

x1 = 5.63
x2 = 5.65
print(float('%.2f' % round(x1,1)))  # gives you '5.6'
print(float('%.2f' % round(x2,1)))  # gives you '5.7'

산출:

5.6
5.7

0

여기에서 라운드 실패를 볼 수 있습니다. 이 두 숫자를 소수점 첫째 자리로 반올림하려면 어떻게해야합니까? 23.45 23.55 내 교육은이 값을 반올림하여 다음을 얻어야한다는 것입니다. 23.4 23.6 "규칙"은 이전 숫자가 홀수이면 반올림해야하고 이전 숫자가 짝수이면 반올림하지 않아야한다는 것입니다. 파이썬의 round 함수는 단순히 5를 자릅니다.


1
당신이 말하는 것은 "은행가의 반올림" 이며, 반올림을 수행하는 다양한 방법 중 하나입니다.
Simon MᶜKenzie

0

문제는 마지막 숫자가 5 일 때만 발생합니다. 예. 0.045는 내부적으로 0.044999999999999로 저장됩니다 ... 마지막 숫자를 6으로 늘리고 반올림 할 수 있습니다. 원하는 결과를 얻을 수 있습니다.

import re


def custom_round(num, precision=0):
    # Get the type of given number
    type_num = type(num)
    # If the given type is not a valid number type, raise TypeError
    if type_num not in [int, float, Decimal]:
        raise TypeError("type {} doesn't define __round__ method".format(type_num.__name__))
    # If passed number is int, there is no rounding off.
    if type_num == int:
        return num
    # Convert number to string.
    str_num = str(num).lower()
    # We will remove negative context from the number and add it back in the end
    negative_number = False
    if num < 0:
        negative_number = True
        str_num = str_num[1:]
    # If number is in format 1e-12 or 2e+13, we have to convert it to
    # to a string in standard decimal notation.
    if 'e-' in str_num:
        # For 1.23e-7, e_power = 7
        e_power = int(re.findall('e-[0-9]+', str_num)[0][2:])
        # For 1.23e-7, number = 123
        number = ''.join(str_num.split('e-')[0].split('.'))
        zeros = ''
        # Number of zeros = e_power - 1 = 6
        for i in range(e_power - 1):
            zeros = zeros + '0'
        # Scientific notation 1.23e-7 in regular decimal = 0.000000123
        str_num = '0.' + zeros + number
    if 'e+' in str_num:
        # For 1.23e+7, e_power = 7
        e_power = int(re.findall('e\+[0-9]+', str_num)[0][2:])
        # For 1.23e+7, number_characteristic = 1
        # characteristic is number left of decimal point.
        number_characteristic = str_num.split('e+')[0].split('.')[0]
        # For 1.23e+7, number_mantissa = 23
        # mantissa is number right of decimal point.
        number_mantissa = str_num.split('e+')[0].split('.')[1]
        # For 1.23e+7, number = 123
        number = number_characteristic + number_mantissa
        zeros = ''
        # Eg: for this condition = 1.23e+7
        if e_power >= len(number_mantissa):
            # Number of zeros = e_power - mantissa length = 5
            for i in range(e_power - len(number_mantissa)):
                zeros = zeros + '0'
            # Scientific notation 1.23e+7 in regular decimal = 12300000.0
            str_num = number + zeros + '.0'
        # Eg: for this condition = 1.23e+1
        if e_power < len(number_mantissa):
            # In this case, we only need to shift the decimal e_power digits to the right
            # So we just copy the digits from mantissa to characteristic and then remove
            # them from mantissa.
            for i in range(e_power):
                number_characteristic = number_characteristic + number_mantissa[i]
            number_mantissa = number_mantissa[i:]
            # Scientific notation 1.23e+1 in regular decimal = 12.3
            str_num = number_characteristic + '.' + number_mantissa
    # characteristic is number left of decimal point.
    characteristic_part = str_num.split('.')[0]
    # mantissa is number right of decimal point.
    mantissa_part = str_num.split('.')[1]
    # If number is supposed to be rounded to whole number,
    # check first decimal digit. If more than 5, return
    # characteristic + 1 else return characteristic
    if precision == 0:
        if mantissa_part and int(mantissa_part[0]) >= 5:
            return type_num(int(characteristic_part) + 1)
        return type_num(characteristic_part)
    # Get the precision of the given number.
    num_precision = len(mantissa_part)
    # Rounding off is done only if number precision is
    # greater than requested precision
    if num_precision <= precision:
        return num
    # Replace the last '5' with 6 so that rounding off returns desired results
    if str_num[-1] == '5':
        str_num = re.sub('5$', '6', str_num)
    result = round(type_num(str_num), precision)
    # If the number was negative, add negative context back
    if negative_number:
        result = result * -1
    return result

0

또 다른 가능한 옵션은 다음과 같습니다.

def hard_round(number, decimal_places=0):
    """
    Function:
    - Rounds a float value to a specified number of decimal places
    - Fixes issues with floating point binary approximation rounding in python
    Requires:
    - `number`:
        - Type: int|float
        - What: The number to round
    Optional:
    - `decimal_places`:
        - Type: int 
        - What: The number of decimal places to round to
        - Default: 0
    Example:
    ```
    hard_round(5.6,1)
    ```
    """
    return int(number*(10**decimal_places)+0.5)/(10**decimal_places)

-4

이건 어떤가요:

round(n,1)+epsilon

반올림이 엡실론에 의해 라운드 수에서 일관되게 벗어난 경우에만 작동합니다. 경우 epsilon = .000001다음은 round(1.0/5.0, 1) + epsilon정확한 표현 0.2을 가지고 그것을 0.00001 만들 것입니다. 엡실론이 round 함수 내에 있으면 똑같이 나쁜 문제가 발생합니다.
마이클 스캇 커스버트
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.