반응형
Python에서 round함수는 오사오입 법칙을 따른다.
사사오입
사사오입(四捨五入)
십진법에서는 다음과 같이 반올림을 한다.
- 반올림 할 자리를 구한다.
4 이하이면 0으로 버리고 5 이상이면 0으로 버린 후 윗자리에 1을 더한다.
사사오입의 예
- 73
- 일의 자리에서 반올림: 70
- 십의 자리에서 반올림: 100
- 51.6137
- 소수점 넷째 자리에서 반올림: 51.614
- 소수점 셋째 자리에서 반올림: 51.61
- 소수점 둘째 자리에서 반올림: 51.6
- 소수점 첫째 자리에서 반올림: 52
- 일의 자리에서 반올림: 50
- 십의 자리에서 반올림: 100
오사오입
반올림에서 5 미만의 숫자는 버림 하며 5 초과의 숫자는 올림한다.올림 한다. 5의 경우에는 5의 앞자리가 홀수인 경우엔 올림을 하고 짝수인 경우엔 버림을 하여 짝수로 만들어준다. 예를 들어 53.45는 53.4로, 32.75는 32.8로 반올림한다. 이를 오사오입(round-to-nearest-even)이라고 한다. 자연과학 및 공학의 유효 숫자에서 많이 쓴다.
출처 : https://ko.wikipedia.org/wiki/반올림
그래서 사사오입의 방식으로 반올림을 하려면 별도로 구현해야 한다.
구현코드
## 1번 방법
def round_half_up(num, dec=0):
from decimal import Decimal
# 3.892857142857143 5.869642857142857 9.7625 9.762 9.763
num = list(str(num))
if "." not in num:
# 자연수
return int("".join(num))
idx = num.index(".")
if len(num) - 1 <= idx + dec:
# dec보다 낮은 소수점 자리수
return float("".join(num))
if int(num[idx + dec + 1]) >= 5:
# 반올림이 필요한 경우
num = "".join(num[: idx + dec + 1])
left = f"0.{'0'*(dec-1)}1"
return float(Decimal(num) + Decimal(left))
else:
num = float("".join(num[: idx + dec + 1]))
return num
## 2번 방법
import math
def round_half_up(n, dec=0):
multiplier = 10**dec
return math.floor(n * multiplier + 0.5) / multiplier
1, 2번 어떤 방법이든 상관없다!
착각하기 쉬운 방법
f"{123.4556:.3f}"
# 출력 : 123.456
구글링을 하다 보면 f-string을 이용하면 round를 구현할 수 있다고 쓰여있는데, 막상 해보면 round와 똑같은 오류를 범한다.
검증용 코드
import random
def round_half_up(num, dec=0):
from decimal import Decimal
# 3.892857142857143 5.869642857142857 9.7625 9.762 9.763
num = list(str(num))
if "." not in num:
# 자연수
return int("".join(num))
idx = num.index(".")
if len(num) - 1 <= idx + dec:
# dec보다 낮은 소수점 자리수
return float("".join(num))
if int(num[idx + dec + 1]) >= 5:
# 반올림이 필요한 경우
num = "".join(num[: idx + dec + 1])
left = f"0.{'0'*(dec-1)}1"
return float(Decimal(num) + Decimal(left))
else:
num = float("".join(num[: idx + dec + 1]))
return num
for i in range(100000):
a = random.randint(10000, 100000) / random.randint(1000, 10000)
b = random.randint(10000, 100000) / random.randint(1000, 10000)
c = a + b
if float(f"{c:.3f}") != round(c, 3) or float(f"{c:.3f}") != round_half_up(c, 3):
print(a, b, c, f"{c:.3f}", round(c, 3), round_half_up(c, 3))
반응형
'프로그래밍 공부(정리) > Python' 카테고리의 다른 글
[PDFKIT] python에서 html을 pdf로 변환하기 - 사전준비 (0) | 2023.02.19 |
---|---|
[Python] Numpy - np.log, np.log2, np.log10, np.log1p 함수 (0) | 2022.01.06 |
[Python] Opencv - 이미지 사이즈 확인 (shape 함수) (0) | 2022.01.05 |
댓글