상세 컨텐츠

본문 제목

[python] 정밀한 소수점 자리가 필요할때 쓰는 decimal

Python

by 메타샤워 2023. 11. 23. 16:41

본문

파이썬은 숫자 데이터를 다루는 코드를 작성하기에 아주 뛰어난 언어이다.

파이썬의 정수타입은 현실적인 크기의 값을 모오두 표현할 수 있다.

매정밀도 부동 소수점 타입은 IEEE 754 표준을 적극적으로 따르고 있다.

파이썬 언어는 허수 값을 표현하는 표준 복소수 타입도 제공한다.

그러나 이것만으로는 산술적 상황을 충족하지 못할 수 있다.

 

예를 들어서 고객에게 부과할 국제 전화 요금을 계산한다고 가정해보자.

고객이 몇 분, 몇 초간 통화했는지 알고있다고 하자 (ex 3m 42s) 

또한 미국에서 남극 대륙을 건너 통화했을 떄의 요율(분당 $1.45)등도 정해져 있다.

그러다면 요금을 얼마를 부과해야 할까?

 

부동 소수점 연사으로 계산한 요금은 합리적처럼 보이기도 한다.

 

rate = 1.45
seconds = 3 * 60 + 42
cost = rate * seconds / 60
print(cost)

>>> 
5.364999999999999

 

그러나 센트 단위에 맞추면 고객이 발생시킨 모든 요금을 적절히 포함하도록 반올림하려고 할때 값을 버릴수도 있다.

 

print(round(cost,2))

>>>
5.36

 

* 정확히는 5.37이 맞다.

 

또한 연결 비용이 훨씬 저렴한 곳 사이에서 일어나는 아주 짧은 통화도 지원해야 한다고 해보자,

 

당므은 분당 $0.05 요율로 5초 동안 일어난 통화의 요금을 계산한 것이다.

 

rate = 0.05
seconds = 5
cost = rate * seconds / 60
print(cost)

>>>
0.004166666666666667

 

부동 소수점의 결과가 너무 작아서 반올림하면 0이 된다. 

 

하지만 이렇게 계산하면 절대 안된다.

 

print(round(cost, 2))

>>>
0.0

 

해결책은 내장모듈 decimal의 Decimal 클래스를 사용하는 것이다. 

Decimal 클래스는 기본적으로 소수점이 28자리인 고정 소수점 연산을 제공한다.

필요하면 자릿수를 더 늘릴 수도 있다. 

Decimal을 이용하면 IEEE 754 부동 소수점 수의 정확도 문제를 피해갈 수 있다.

또한 반올림 연산을 더 세밀하게 제어 할수 있다.

 

에를 들어 Decimal로 남극 통화 요금을 다시 계산하면 근사값이 아닌 아주 정확한 요금이 나온다.

 

rate = Decimal('1.45')
seconds = Decimal('222') # 3 * 60 + 42
cost = rate * seconds / Decimal('60')
print(cost)

>>>
5.365

 

Decimal 클래스에는 원하는 반올림 동작에 따라 필요한 소수점 위치로 정확하게 반올림하는 내장 함수가 있다.

 

rounded = cost.quantize(Decimal('0.01'), rounding=ROUND_UP)
print(rounded)

>>>
5.37

 

 

이 방식으로 quantize 메서드를 사용하면 짧고 저렴한 통화에 해당하는 적은 통화료로 적절하게 처리할 수 있다. 

 

Decimal이 고정 소수점 수에도 잘 동작하지만 아직도 정확도 면에서는 제약이 있다. 

예를들어 1/3은 근사값으로 계산된다. 

정확도에 제한이 없는 유리수를 표현하려면 내장 모듈 fractions의 Fraction 클래스를 사용해야 한다.

 

 

'Python' 카테고리의 다른 글

[python] 버전 확인 하기  (0) 2023.11.23
[python]List와 Tuple의 차이점  (1) 2023.11.14
[Python] anaconda vs pipenv 비교해보았다. 6가지  (0) 2023.07.25

관련글 더보기