Post

[Github blog] 부동소수점

문제

Python에서 실수형 (float)를 다룰 때 다음과 같은 오류가 발생할 수 있다.

1
2
3
4
5
6
>>> 0.1 * 3 == 0.3
False
>>> 1.2 - 0.1 == 1.1
False
>>> 0.1 * 0.1 == 0.01
False

눈으로 봤을 때는 전혀 이상이 없기 때문에 이러한 오류를 겪었을 때 많이 당황했었던 기억이 있다.


원인

실수 표현 방식[1]

컴퓨터는 모든 수를 0과 1로 이루어진 2진수로 표현하고, 이는 실수도 마찬가지이다.
실수를 표현하는 방식은 크게 2가지 방식이 있다.

  1. 고정 소수점 (fixed point) 방식
  2. 부동 소수좀 (floating point) 방식

그 중에서도 Python은 실수를 부동소수점으로 표현한다.


부동소수점[2]

부동 소수점 방식은 하나의 실수를 부호(sign), 가수(mantissa), 지수(exponent)로 나누어 표현하는 방식을 의미한다.

부호는 전체 수가 양수 또는 음수를 표현하고,

지수는 2의 지수를 나타내며,

가수는 소수 이하를 표시합니다.

해결[1][3]

decimal.Decimal, math.fsum(), round(), float.as_integer_ratio(), math.is_close() 등의 함수를 사용해 문제를 해결할 수 있다.

  1. decimal.Decimal: 숫자를 10진수로 처리하여 정확한 소수점 자릿수를 표현
    1
    2
    3
    4
    5
    
    >>> 0.1 + 0.2 == 0.3
    False
    >>> from decimal import Decimal
    >>> Decimal('0.1') + Decimal('0.2') == Decimal('0.3')
    True
    


  2. round(): 숫자를 반올림해주는 내장 (built-in) 함수
    1
    2
    3
    4
    
    >>> 0.1 + 0.1 + 0.1 == 0.3
    False
    >>> round(0.1 + 0.1 + 0.1, 10) == round(0.3, 10)
    True
    


    결론

    쉽고 간단해 보이지만 관련된 개념이 없었을 당시에는 매우 찾기 어려운 오류였다.

    오류가 발생하는 원인을 알았기 때문에, 위의 방식 외에도 필요와 목적에 맞게 알맞은 방식으로 해결 할 수 있을 것 같다.



참조 (References)

  1. 파이썬 float형 부동소수점 오차가 발생하는 이유
  2. 컴퓨터에서 실수의 표현 (Fixed Point, Floating Point, Single Precision, Double Precision)
  3. 파이썬에서 부동소수점 오차 해결하기
This post is licensed under CC BY 4.0 by the author.