본문 바로가기
파이썬

파이썬 함정카드, round() 알아보기

by Devry 2024. 1. 30.

엑셀 데이터를 읽어서 특정 동작을 하는 외주 프로그램에서 문제가 발생했다.

당연하게도 읽은 값을 입력하면 서로 동일해야 하지만 딱 하나가 읽을 땐 2.3의 값이 2.2로 입력되었다.

결론부터 말하자면,

부동소수점으로 인해 예상되는 동작과 실제 동작이 다른 round 메서드 때문이었다

 


파이썬의 내장 메서드인 round는 모두가 예상하듯이 소수점을 반올림하는 함수이고 깊게 알아볼 이유도 없어 보인다

구글의 최상단에 뜨는 블로그를 들어가도 '반올림에 사용된다' 정도만 언급되어 있고 chatGPT도 반올림 함수의 예시로 round를 알려준다

 

하지만 round메서드는 우리가 일반적으로 의미하는 반올림과 다른 반올림을 사용한다

우리가 생각하는 반올림이면 round(2.5) = 3이 나와야 할 텐데?

 

round의 올바른 사용법을 찾기 위해 파이썬의 공식 문서를 찾아보면 답을 알 수 있는데 round 메서드는 반올림하려는 수가 올림, 내림했을 때 동일한 차이가 나는 경우 짝수 값으로 반올림을 한다

 

매우 중요한 정보임에도 오해하기 쉽기 때문에 round 메서드에 대한 설명이 필요하다고 느꼈다

나의 경우 외주 작업이 한번 오작동하면 고객과 신뢰가 많이 깨지게 될 수 있고

코딩테스트를 준비하는 사람은 round를 잘못 사용해서 시험에서 탈락할 수도 있다

 

해결법은?

내장 decimal 라이브러리로 반올림 방법을 설정하여 사용할 수 있다

decimal.getcontext().rounding = decimal.ROUND_HALF_UP  를 입력하여 우리가 알고 있는 반올림을 사용하도록 설정한다

decimal.Decimal("반올림 하려는 수").quantize(decimal.Decimal("표시할 자릿수 표현식"))

import decimal

decimal.getcontext().rounding = decimal.ROUND_HALF_UP
decimal.Decimal("2.25").quantize(decimal.Decimal("1"))
# Decimal('2')
decimal.Decimal("2.25").quantize(decimal.Decimal("1.0"))
# Decimal('2.3')
decimal.Decimal("2.25").quantize(decimal.Decimal("1"))
# Decimal('2.25')

 

주의할 점은

- 앞부분의 decimal.Decimal()에 인자로 문자열을 주어야 하고, 숫자를 넣으면 다르게 동작한다

- decimal.ROUND_HALF_UP을 설정해 주는 부분은 decimal을 사용하는 부분과 같은 컨텍스트 여야 한다

 

결론

1 블로그는 역시 틀린 글이 많고 당연히 맞는 말 같아서 의심하기 힘들다. 메서드를 설명할 때 공식 문서를 참조하는 습관을 들이자
2 프로그래밍의 근본 원리인 부동소수점에 대한 이해가 더 필요하다

 

참고 블로그

https://m.blog.naver.com/youndok/222218536425
https://blockdmask.tistory.com/418
https://trivia-starage.tistory.com/201

 

 

 

 

댓글