[Python] 파이썬 부동 소수점 오차 해결 (decimal 모듈 사용법)

컴퓨터에서 소수는 어떻게 계산할 수 있을까요? 컴퓨터는 숫자를 이진법으로 표현하기 때문에 먼저 10진법의 소수를 이진법으로 변환한 뒤 연산을 해야 합니다. 이 과정에서 대부분의 소수는 오차가 발생하게 되는데요. 왜냐하면 십진법의 소수를 2의 음의 제곱으로 이진법으로 변환해주어야 하는데 많은 소수들이 완벽하게 변환될 수 없기 때문입니다. 무한소수가 되어버리는 경우들이 상당히 많습니다.

 

또한 무한소수는 변수에 저장될 수 없습니다. 메모리의 크기에 한계가 있기 때문입니다. 그래서 근사값으로 소수를 저장합니다. 메모리가 허용하는 범위 내에서 소수를 최대한 저장하고 끝의 자리에서 반올림을 해서 저장하는 것입니다. 이 과정에서도 불가피하게 오차가 발생합니다. 예를 들자면 0.1은 이진수로 정확히 표현되지 않아서 근사값으로 저장되기에 0.1로 그 어떤 연산을 해도 오차가 발생합니다.

 

부동소수점 오차

print(0.1 + 0.2)

결과 : 0.30000000000000004

 

실제로 확인해봐도 0.1 + 0.2 = 0.30000000000000004이라는 결과가 나옵니다. 파이썬에서 실수는 float 타입으로 계산되며 float은 부동소수점 방식으로 소수를 표현합니다. 그리고 위에서 설명한 이유로 인해 오차가 발생하죠. 그래서 이를 부동소수점 오차라고 합니다. 물론 아주 미세한 수치이겠지만 금융이나 우주항공, 방산과 같은 프로그램에서는 이 미세한 수치가 큰 영향을 줄 수도 있는 만큼 정확한 계산이 필요한 경우도 있을 수 있습니다. 이러한 문제를 해결하기 위해 파이썬에서는 decimal 모듈을 제공하고 있습니다.

 


 

 파이썬의 decimal 모듈 사용법 

decimal 모듈은 정확한 소수 연산을 제공해 주는 파이썬의 라이브러리입니다. 이 모듈을 import 하여 사용하면 부동 소수점 오차를 피하고 정확한 연산을 수행할 수 있습니다. 단 decimal 모듈을 사용하면 float 자료형을 사용하는 것보다 속도가 느리다는 점은 유의해주셔야 합니다.

 

Decimal 데이터 타입 생성

from decimal import Decimal

number = Decimal('0.1')

Decimal 데이터 타입을 생성할 때는 decimal 모듈을 먼저 import 하고 Decimal() 생성자를 사용하시면 됩니다. 예를 들어 0.1을 Decimal 타입으로 생성하려면 위와 같이 사용하면 됩니다.

 

 

정확한 실수 계산 제공

from decimal import Decimal

x = Decimal('0.1')
y = Decimal('0.2')

print(x + y)  # 결과: Decimal('0.3')

결과 : 0.3

 

위와 같이 decimal 모듈을 사용하면 부동 소수점 숫자의 오차를 피하고 정확한 실수 계산을 할 수 있습니다. 그렇기 때문에 금융이나 우주과학과 같이 정밀한 계산이 필요한 프로그램에서 적절하게 사용할 수 있습니다.

 

 

정밀도 제어

from decimal import Decimal, getcontext

getcontext().prec = 10  # 소수점 이하 10자리까지 정밀도 설정
a = Decimal('0.12345')
b = Decimal('1.23456')
result = a * b
print(result) # 결과 : 0.1524064320

결과 : 0.1524064320

 

너무 정확한 소수의 계산은 성능악화를 초래합니다. 그래서 Decimal에는 정밀도를 제어할 수 있는 기능이 있는데요.  getcontext() 메서드를 사용하면 소수 계산의 정밀도를 제어할 수 있으며, 위와 같이 연산에서 소수점 이하의 자릿수를 지정할 수 있습니다.

 

 

반올림 및 올림

from decimal import Decimal, ROUND_UP

number = Decimal('10.333')
rounded = number.quantize(Decimal('0.01'), rounding=ROUND_UP)  # 결과: Decimal('10.34')
print(rounded)

결과 : 10.34

 

Decimal 객체를 사용하여 위와 같이 소수를 반올림, 올림을 할 수도 있습니다.

댓글

Designed by JB FACTORY