📍 절사 평균과 round(반올림) 함수 그리고 부동소수점 비교
절사평균 - 위키피디아 란, 편차가 큰 자료의 경우 산술평균이 적합하지 않으므로 자료의 총 개수에서 일정 비율만큼 가장 큰 부분과 가장 작은부분을 제거 후 평균을 산출하는 방법이다.
예를들어, `n=5`개인 표본집단에서 15%의 절사평균
을 구한다고 하면 전체 값의 상위 5 * 0.15 = 0.75
, 하위 5 * 0.15 = 0.75
개 만큼 제외 후 평균을 구한다는 뜻이다. (문제에 따라 소수점으로 나오게 되면 반올림을 하거나 하지 않는 경우가 있기 때문에 반올림하지 않았다.)
주어진 표본집단 arr
에서 15% 절사평균
을 구한다고 가정하면 (소수점일 때 반올림한다.) python
에서 다음과 같이 작성 할 수 있다. 이때 slicing
을 2가지 방법으로 구현했다.
n = 5
arr = [10, 20, 30, 40, 50]
trunc = round(n * 0.15) # 1, 앞 뒤로 1개씩 제외시키기
print(arr[trunc: -trunc]) # arr[1:-1]
👉🏽 [20, 30, 40]
print(arr[trunc: n-trunc]) # arr[1:4]
👉🏽 [20, 30, 40]
논외로, 알고리즘 문제(예: boj_18110 - solved.ac)에서 `round` 함수를 사용해서 제출하면 오답 판정을 받는데 왜냐하면 python
에서 round
함수를 사용할 때 우리가 알고 있는 반올림 형태인 4사 5입(4
이하는 버리고 5
이상부터 반올림)이 아니라 5사 5입(ROUND_HALF_EVEN
or round_to_nearest_even
: 앞자리가 홀수면 올리고 앞자리가 짝수면 버리는 방법)을 기반으로 실행되기 때문이다.
공학이나 자연과학에서 5사 5입
방법을 많이 사용하는데 맨 뒷자리가 필연적으로 손실되는 계산 특성상 오사오입으로 처리하는 것이 오차가 가장 적기 때문이다. 추가적인 내용이 궁금하다면 부동 소수점의 문제점과 한계(python.org)를 살펴보자.
5사 5입(ROUND_HALF_EVEN
or round_to_nearest_even
)의 예시는 다음과 같다.
print(round(0.5)) # 0
print(round(1.5)) # 2
print(round(2.5)) # 2
print(round(3.5)) # 4
print(round(4.5)) # 4
print(round(5.5)) # 6
결론적으로 부동소수점을 반올림을 할 때 우리가 평소에 사용하는 십진법으로 계산하고 싶다면 직접 함수를 만들거나
, decimal
, `Fraction` 라이브러리를 이용해야 하는데 다음과 같이 사용 할 수 있다.
# 함수 만들기
def round2(num):
return int(num) + (1 if num - int(num) >= 0.5 else 0)
print(round2(0.5)) # 1
print(round2(1.5)) # 2
print(round2(2.5)) # 3
print(round2(3.5)) # 4
print(round2(4.5)) # 5
print(round2(5.5)) # 6
# decimal 라이브러리 사용
from decimal import Decimal
value = Decimal('0.1') * Decimal('0.1')
print(value)
👉🏽 0.01
여담이지만, 두 실수가 같은지 판단하려면 `==` 대신 `math.isclose` 혹은 `sys`를 이용해서 확인 할 수 있다. 참고로 `sys.float_info.epsilon`에 저장된 값은 머신 앱실론(machine epsilon)이라고 부르는데, 어떤 실수를 가장 가까운 부동소수점 실수로 반올림 했을 때 상대 오차는 항상 머신 앱실론 이하다. 그래서 두 값이 같은지 다른지를 비교하려면 비교대상을 머신 앱실론으로 정하고 이보다 작거나 같으면 `True` 처리가 된다.
또, `python 3.5` 이상부터는 `math_isclose` 함수를 사용하여 비교 할 수도 있다.
# epsilon 사용
import math, sys
x = 0.1 + 0.2
print(math.fabs(x - 0.3) <= sys.float_info.epsilon)
👉🏽 True
print(sys.float_info.epsilon)
👉🏽 2.220446049250313e-16 # epsilon 값
# math.isclose 사용
print(math.isclose(0.1 + 0.2, 0.3))
👉🏽 True
reference
'Python > 파이썬 문법 Tips' 카테고리의 다른 글
[ 파이썬(python) ] 공백으로 들어온 int를 공통으로 빼주기 (0) | 2021.07.19 |
---|---|
[ 파이썬(python) ] 2차원 행렬 시계방향으로 한 칸씩 회전하기 (0) | 2021.07.15 |
[ 파이썬(python) ] python에서 음의 정수를 floor 해보기 (0) | 2021.07.01 |
[ 파이썬(python) ] 리스트 중 front, back에서부터 target index까지 어느쪽이 더 가까운지 판단하기 (0) | 2021.06.25 |
[ 파이썬(python) ] 삼각수(계차수열) 나타내기 (0) | 2021.06.20 |
댓글