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.