문제

에 대한 문서 둥근() 함수는 숫자를 전달하고 소수점 이하의 위치는 반올림하도록 지정합니다.그리하여 그것은 ~해야 한다 이 작업을 수행:

n = 5.59
round(n, 1) # 5.6

그러나 실제로는 오래된 부동 소수점 이상한 현상이 나타나 다음과 같은 결과를 얻습니다.

5.5999999999999996

UI를 위해 다음을 표시해야 합니다. 5.6.인터넷을 뒤져 몇 가지를 찾았습니다. 선적 서류 비치 이것은 내 Python 구현에 따라 다릅니다.불행하게도 이것은 내 Windows 개발 컴퓨터와 내가 시도한 각 Linux 서버 모두에서 발생합니다. 여기도 보세요.

내 자신의 라운드 라이브러리를 만드는 것 외에 이 문제를 해결할 수 있는 방법이 있습니까?

도움이 되었습니까?

해결책

저장 방식은 어쩔 수 없지만 최소한 형식은 올바르게 작동합니다.

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

다른 팁

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

"%.1f" % n

Decimal 모듈을 사용하면 'round' 기능을 사용하지 않고도 근사치를 얻을 수 있습니다.특히 화폐 애플리케이션을 작성할 때 반올림에 사용한 것은 다음과 같습니다.

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

그러면 16.20인 10진수가 반환됩니다.

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

>>> 5.6
5.5999999999999996
>>> 

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

파이썬에는 십진수 산술 모듈 그게 필요하다면.

그렇게 하면 '5.6'을 얻습니다. str(round(n, 1)) 그냥 대신에 round(n, 1).

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

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

그런 다음 로캘의 소수 구분 기호를 삽입하여 숫자를 표시합니다.

하지만, 지미의 대답 더 나은.

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

다음을 살펴보세요. 십진수 모듈

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

그리고

소수점 숫자는 정확히 표현 될 수 있습니다.대조적으로, 1.1 및 2.2와 같은 숫자는 이진 부동물 지점에서 정확한 표현이 없습니다.최종 사용자는 일반적으로 바이너리 플로팅 포인트와 마찬가지로 1.1 + 2.2가 3.3000000000000003으로 표시 될 것으로 기대하지 않습니다.

Decimal은 부동 소수점 연산이 필요한 앱을 쉽게 작성할 수 있는 일종의 연산을 제공하며 또한 회계와 같이 사람이 읽을 수 있는 형식으로 결과를 제시해야 합니다.

참으로 큰 문제입니다.다음 코드를 사용해 보세요.

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의 거듭제곱인 분수의 가장 가까운 유한 합으로 저장됩니다.

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

mystring = "%.2f" % 5.5999

printf 빨판.

print '%.1f' % 5.59  # returns 5.6

완벽하게 작동

format(5.59, '.1f') # to display
float(format(5.59, '.1f')) #to round

내가 뭐하는 거지:

int(round( x , 0))

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

그래서

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

나는 이 답변이 문자열 형식을 지정하는 것보다 더 효과적이라고 생각하며 round 함수를 사용하는 것이 더 합리적이라고 생각합니다.

암호:

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

여기에서 라운드가 실패하는 것을 볼 수 있습니다.이 두 숫자를 소수점 이하 한 자리로 반올림하고 싶다면 어떻게 해야 할까요?23.45 23.55 내 교육은 이것들을 반올림하는 것입니다.23.4 23.6 "규칙"은 이전 숫자가 홀수 인 경우 반올림해야한다는 것입니다.Python의 round 함수는 단순히 5를 자릅니다.

문제는 마지막 숫자가 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

는 어때:

round(n,1)+epsilon
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top