본문 바로가기
Insights

Python 에서의 round 함수의 동작원리

by 준벨롭 2024. 3. 17.
Python에서 round메서드 안에 2.5라는 값을 넣으면 round(2.5) 어떤 값이 나올까? 
놀랍게도 3이 아닌 2라는 수가 나온다!
이번 포스팅부터는 알고리즘 문제를 풀며 생긴 의문들을 정리하고자 한다.
  • 백준 18110번 solved.ac 문제 요구사항에 맞게 구현했지만, 틀렸다는 결과를 받았음.

구현 코드(오답)

N = int(input())
if N == 0:
    print(0)
else:
    lst = []
    s = round(N*15/100)	# N의 15%의 값을 반올림
    e = N-s	# N의 85%의 해당하는 값을 반올림
    # print(s)
    # print(e)
    for _ in range(N):
        lst.append(int(input()))
    lst.sort()	# 값을 넣고 정렬한다.
    print(round(sum(lst[s:e])/(e-s))) # lst의 하위 15%, 상위 15% 를 제외한 값을 추출한다.
    # 그 후 갯수만큼 나눠 평균을 구한다.

 

2. 공식문서 확인

  • 다양한 케이스를 통해 예외상황을 확인결과 round 메서드가 원인임을 알아냈다.
  • float에 대한 round의 동작은 예상과 다를 수 있다는 공식문서를 확인할 수 있었다.

 

3. 조사내용

  • 부동 소수점 산술
  • 오사오입

 

3-1. 부동 소수점 산술

  • 거의 모든 프로그래밍 언어에서 발생가능한 문제이다.
    부동 소수점에 관한 내용은 추후에 다루도록 하겠다.

 

3-2. 오사오입

  • Round half to even(Banker's rounding)을 기본으로 채택하고 있기 때문이다.

왜 사용하는가?

- 예를 들어 0.5+1.5+2.5+3.5 = 8이다.

- 기존 반올림으로는 1+2+3+4 = 10이라는 값이 나온다.

- Round half to even 기법을 채택하면 0+2+2+4 = 8로 오차가 줄어드는 결과를 확인할 수 있다.

- 기존 반올림 대비 편향을 줄일 수 있는 장점이 있다.

4. 문제 해결 방법

  • 새로운 함수 작성

 

1. 0.5를 더하고 버림을 하는 방법(or 0.5를 빼고 올리는 방법과 같다)

import math

def round_up_half(num):
    return math.floor(num + 0.5)

 

2. 실수값에서 정수 값을 뺀 값의 차이가 0.5 이상이라면 1을 더하고, 아니면 정수를 반환하는 방법(내가 채택한 방법)

import math

def num(n):
    if (n-int(n)) >= 0.5:
        return int(n)+1
    else:
        return int(n)

 

3. Decimal 모듈 사용

from decimal import Decimal

def dec(num):
    return Decimal('num')

참고사항 : Decimal 모듈을 사용할 때는 문자열로 받아야한다.

 

5. 배운점

기존의 알고있던 반올림과는 약간 다른 round 메서드의 사용법을 알았고, 결국 문제 해결에 성공했다.

Banker's rounding을 어째서 사용하는가

- 근사 오차를 줄일 수 있음!

컴퓨터에서의 실수 처리방법

- 부동 소수점, 고정 소수점

- 그리고 각각의 장, 단점들(추가 조사 필요)

import math

def num(n):
    if (n-int(n)) >= 0.5:
        return int(n)+1
    else:
        return int(n)

N = int(input())
if N == 0:
    print(0)
else:
    lst = []
    s = num(N*0.15)
    # print(s)
    for _ in range(N):
        lst.append(int(input()))
    lst.sort()
    answer = lst[s:N-s]
    print(num(sum(answer)/len(answer)))

 

6. 추가 조사가 필요한 내용들

1. 부동소수점

2. 고정소수점

3. Deciaml 모듈 사용법

728x90