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
'Insights' 카테고리의 다른 글
컴퓨터에서의 실수 표현인 고정 소수점, 부동 소수점 (0) | 2024.03.25 |
---|