[python] 파이썬에서 부동소수점 다루는법

- 3 mins

부동소수점 처리

다음과 같은 코드가 있다.

print(f"0.1 + 0.2 : {0.1 + 0.2}")
print(f"0.1 + 0.2 == 0.3 : {0.1 + 0.2 == 0.3}")

결과가 어떨까?

예상되는 결과는 0.3 , True일 것이다.

실행해보자.

0.1 + 0.2 : 0.30000000000000004
0.1 + 0.2 == 0.3 : False

예상과 다른 결과가 나왔다.

0.1과 0.2를 더했는데 0.3이 아닌 0.30000000000000004가 나왔다.


다른 대부분의 프로그래밍 언어처럼,

파이썬 또한 실수를 부동소수점 방식으로 표현하기 때문이다.

부동소수점은 실수를 정확하게 표현할 수 없는 문제가 있다.


부동소수점으로 실수를 표현하면 소숫점 이하가 무한히 반복되기 때문에,

특정 시점에 반올림하여 실제 값과 비슷한 근사값을 구하게 된다.

이렇게 실제 값과 근사값 사이에 발생하는 오차를 반올림 오차(rounding error)라고 하는데,

이 차이는 항상 머신 엡실론(machine epsilon)값 보다 작다.


이와 같은 특성을 이용해서 실수비교를 수행하면 된다.

근사 값에서 실제 값을 뺀 값이 머신 엡실론보다 작다면, 이는 같은 값으로 취급하면 된다.

머신 엡실론 값은 sys.float_info.epsilon에 저장되어있다.

그럼, 코드를 바꿔보자.

import sys

def compare_floating_point(approx, actual):
    return (True if abs(approx - actual) <= sys.float_info.epsilon else False)

print(f"0.1 + 0.2 : {0.1 + 0.2}")
print(f"0.1 + 0.2 == 0.3 : {compare_floating_point(0.1 + 0.2, 0.3)}")

근사 값과 실제 값을 인자로 받고,

근사 값에서 실제 값을 뺀 값이 머신 엡실론보다 작을 경우 True를 반환하는 함수를 작성했다.

결과를 보자.

0.1 + 0.2 : 0.30000000000000004
0.1 + 0.2 == 0.3 : True

0.1 + 0.2와 0.3의 비교 결과로 True를 반환했다.

파이썬 3.5버전 이상부터는 이러한 기능을 하는 함수가 math.isclose라는 이름으로 내장되어있다.

import math

print(f"0.1 + 0.2 : {0.1 + 0.2}")
print(f"0.1 + 0.2 == 0.3 : {math.isclose(0.1 + 0.2, 0.3)}")

결과는 이전 코드와 동일하다.

또는 다음과 같이 round함수로 소수점 특정 자리 까지만 비교하는 방법도 있다.

print(f"0.1 + 0.2 : {0.1 + 0.2}")
print(f"0.1 + 0.2 == 0.3 : {round(0.1 + 0.2, 1) == round(0.3, 1)}")

또한 Decimal모듈을 이용해 반올림 오차가 없는 고정 소수점을 사용해 비교할수도 있다.

from decimal import Decimal

print(f"0.1 + 0.2 : {0.1 + 0.2}")
print(f"0.1 + 0.2 == 0.3 : {Decimal('0.1') + Decimal('0.2') == Decimal('0.3')}")

이 코드들 또한 모두 True를 반환한다.


숫자를 소숫점 아래까지 비교하는 프로그래밍의 경우, 비교의 결과가 다를경우 정말 치명적인 결과를 낳을 수 있다.

그만큼 숫자를 세밀하게 측정한다는 것은 숫자가 상당히 중요한 분야의 프로그램이라는 의미이고,

숫자가 중요하다는 것은 대부분 금융(쉽게말해 돈)과 관련된 업무일 가능성이 높기때문이다.


경우에따라 소숫점 아래를 무조건 버린다거나 하는 선택은 절대로 피해야할 수도 있고,

소숫 몇자리 아래는 전부 버려도 상관 없는 업무일수도 있다.

모든 프로그래밍이 그렇지만, 특히나 실수형 자료형을 비교할 경우 더욱 신중히 여러 방법중 적절한 방법을 택해야한다.




코딩장이

코딩장이

-장이: [접사] ‘그것과 관련된 기술을 가진 사람’의 뜻을 더하는 접미사.

rss facebook twitter github youtube mail spotify lastfm instagram linkedin google google-plus pinterest medium vimeo stackoverflow reddit quora quora