Back to writing

Decimal - 정확한 소수점 연산하기

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 에서 확인할 수 있습니다.