Back to writing
Decimal - 정확한 소수점 연산하기
파이썬의 기본적인 실수(float) 타입은 이진 부동소수점 방식을 사용하기 때문에 간단한 소수 연산도 미세한 오차가 발생합니다. 부동소수점 방식에서 특정 10진수 수를 2진수로 표현할 수 없는 경우 오차가 발생하며 이러한 문제를 해결하기 위해 Python은 정확한 10진수 연산을 지원하는 decimal 모듈을 제공합니다. 이번 포스팅에서는 decimal 모듈의 개념과 주요 동작 원리를 다뤄보겠습니다.
Decimal 모듈
Decimal객체: 부호(sign), 계수(coefficient), 지수(exponent)로 이루어져 있으며 특수 값(Infinity,NaN,+0,-0)도 처리 가능합니다.Context: precision(유효 자릿수), rounding(반올림 방법), Emin/Emax(지수 범위), traps(예외 발생 여부) 등의 속성을 설정하여 연산 환경을 관리합니다.
from decimal import Decimal, getcontext
getcontext().prec = 6 # 유효 자릿수 설정
a = Decimal('1.23')
b = Decimal((0, (1, 2, 3), -2)) # 같은 값
print(a) # 1.23
print(b) # 1.23
정밀도(precision)와 반올림(rounding)
정밀도는 연산 결과에만 적용되며, 입력 값은 항상 정확한 값을 유지합니다.
from decimal import Decimal, getcontext
getcontext().prec = 6
print(Decimal(1) / Decimal(7)) # 0.142857
getcontext().prec = 28
print(Decimal(1) / Decimal(7)) # 0.1428571428571428571428571429
고정 소수점 연산 quantize
from decimal import Decimal, ROUND_DOWN
TWOPLACES = Decimal('0.01')
print(Decimal('7.325').quantize(TWOPLACES, rounding=ROUND_DOWN)) # 7.32
일시적 연산 환경 설정
localcontext()를 사용하면 일시적으로 context를 변경할 수 있습니다.
from decimal import localcontext, Decimal
with localcontext() as ctx:
ctx.prec = 50 # 50자리까지 정밀도 증가
high_prec_value = Decimal(2) / Decimal(3)
# 블록을 벗어나면 원래의 정밀도로 복구
자릿수가 다른 decimal 객체 연산
자릿수가 다른 decimal 객체 연산 시 두 수의 지수를 비교하여 더 작은 지수를 가진 값의 계수(coefficient)를 지수 차이만큼 곱(또는 이동)해 지수를 같게 만듭니다.
이는 유효 자릿수(getcontext().prec)를 초과하는 자릿수를 버리는 방식으로 이루어집니다.
decimal1: Decimal = Decimal('0.000000000001')
decimal2: Decimal = Decimal('0.2')
print(decimal1 + decimal2) # 0.21
decimal1: Decimal = Decimal('0.1')
decimal2: Decimal = Decimal('0.02')
print(decimal1 + decimal2) # 0.12
decimal1: Decimal = Decimal('0.0000000000000000000000000000000000000000000000001')
decimal2: Decimal = Decimal('0.2')
print(decimal1 + decimal2) # 0.2000000000000000000000000000, default precision 28
다른 언어의 부동 소수점 처리
추가적으로 여러 언어의 부동 소수점 처리에 대한 내용은 0.30000000000000004.com 에서 확인할 수 있습니다.