본문으로 건너뛰기
김신건의 로그

[Python] float, Decimal, Fraction

· 수정 · 📖 약 2분 · 614자/단어 #python #float #decimal #fraction #number #basics
python float, python decimal, python fraction, 부동소수점, 정밀 산술

정의

Python의 실수 산술은 세 가지 타입을 제공한다.

  • float: IEEE 754 double precision (64비트). C double과 동일. 빠르지만 부정확.
  • decimal.Decimal: 임의 정밀도 십진수. 금융·통화 계산용. 느리지만 정확.
  • fractions.Fraction: 분수 표현. 유리수 정확 계산. 가장 느림.

float: IEEE 754 double

python
x = 0.1 + 0.2
print(x)
print(x == 0.3)
print(repr(x))    # 모든 비트 표시
결과
0.30000000000000004
False
0.30000000000000004

0.10.2는 2진 부동소수로 정확히 표현되지 않는다. 누적 오차가 발생한다.

부동소수 비교

직접 == 대신 math.isclose()를 써라.

python
import math
print(math.isclose(0.1 + 0.2, 0.3))  # True
print(math.isclose(0.1 + 0.2, 0.3, abs_tol=1e-9))
결과
True
True

특수 값

import math
math.inf       # 양의 무한대
-math.inf      # 음의 무한대
math.nan       # Not a Number

float("inf")
float("-inf")
float("nan")

math.isnan(math.nan)   # True
math.isinf(math.inf)   # True
# NaN은 자기 자신과도 != 다.
math.nan == math.nan   # False

float 정보

import sys
sys.float_info
# epsilon=2.22e-16, mant_dig=53, max=1.79e+308, min=2.22e-308

Decimal: 정확한 십진 산술

python
from decimal import Decimal, getcontext

a = Decimal("0.1") + Decimal("0.2")
print(a)
print(a == Decimal("0.3"))

# 정밀도 설정
getcontext().prec = 50
print(Decimal(1) / Decimal(7))
결과
0.3
True
0.142857142857142857142857142857142857142857142857143

중요: Decimal(0.1)은 float를 통하므로 부정확. 반드시 문자열로 생성 Decimal("0.1").

python
from decimal import Decimal
print(Decimal(0.1))         # float에서 변환 (부정확)
print(Decimal("0.1"))       # 문자열에서 (정확)
결과
0.1000000000000000055511151231257827021181583404541015625
0.1

금융 계산 예시

from decimal import Decimal, ROUND_HALF_UP

price = Decimal("19.99")
tax_rate = Decimal("0.13")
tax = (price * tax_rate).quantize(Decimal("0.01"), rounding=ROUND_HALF_UP)
total = price + tax
# Decimal('22.59')

Fraction: 유리수 정확 계산

python
from fractions import Fraction

a = Fraction(1, 3)
b = Fraction(1, 6)
print(a + b)
print(a * 6)

# float에서 생성 (주의: 부정확한 분수)
print(Fraction(0.1))
print(Fraction("0.1"))
결과
1/2
2
3602879701896397/36028797018963968
1/10

Fraction(0.1)은 float의 실제 비트 표현을 분수로 옮긴 결과다. 문자열 입력이 안전하다.

언제 무엇을 쓰나

상황선택
과학 계산, ML, 통계float (NumPy 권장)
금융, 통화, 회계Decimal
기호 수학, 유리수 정확 비교Fraction
빠른 정수 산술int (임의 정밀도)

변환

int(3.7)          # 3 (소수 버림)
float("3.14")     # 3.14
float("inf")      # inf
Decimal("1.5")
Fraction("3/7")

round(3.14159, 2) # 3.14
round(2.5)        # 2 (bankers' rounding: 짝수로)
round(3.5)        # 4

round()bankers’ rounding(반올림이 정확히 0.5일 때 짝수로)을 쓴다. 일반적인 사사오입은 decimal.Decimal.quantize(..., ROUND_HALF_UP).

IEEE 754 double precision 구조

flowchart LR
    S["부호 1bit"] --> E["지수 11bit"] --> M["가수 52bit"]
비트필드의미
63부호0 양수, 1 음수
62-52지수biased exponent (바이어스 1023)
51-0가수fraction, 암묵 leading 1

float 유효 십진 자릿수: 약 15.9자리. sys.float_info.epsilon = 2.22e-16.

math 모듈 주요 함수

import math

# 반올림 계열
math.floor(3.7)     # 3 (내림)
math.ceil(3.2)      # 4 (올림)
math.trunc(-3.7)    # -3 (0 방향)
round(3.14159, 2)   # 3.14

# 근사 비교
math.isclose(0.1 + 0.2, 0.3)               # True
math.isclose(1e6, 1e6 + 1, rel_tol=1e-6)  # True (상대 오차 기준)

# 특수 값 판별
math.isnan(float('nan'))   # True
math.isinf(float('inf'))   # True
math.isfinite(42.0)        # True

# 수학 함수
math.sqrt(2)           # 1.4142...
math.log(math.e)       # 1.0
math.log2(8)           # 3.0
math.log10(1000)       # 3.0
math.pow(2, 10)        # 1024.0 (항상 float)

# 정밀 합산
math.fsum([0.1, 0.2, 0.7])   # 1.0 (sum() 과 달리 누적 오차 방지)

성능 비교

import timeit

# float: 가장 빠름
timeit.timeit('0.1 + 0.2', number=10_000_000)
# ~0.3s

# Decimal: 약 10배 느림
timeit.timeit(
    'Decimal("0.1") + Decimal("0.2")',
    setup='from decimal import Decimal',
    number=10_000_000,
)
# ~3s

# Fraction: 약 30배 느림
timeit.timeit(
    'Fraction(1,10) + Fraction(1,5)',
    setup='from fractions import Fraction',
    number=1_000_000,
)
# ~1s per million
타입상대 속도정밀도주요 용도
float1x (기준)53비트 이진과학/ML/통계
Decimal~10x 느림임의 정밀도 10진금융/통화/회계
Fraction~30x 느림완전 유리수기호 수학
intfloat 급임의 정밀도 정수정수 산술

부동소수 흔한 함정

WARNING

  1. 직접 == 비교: 0.1 + 0.2 == 0.3False. math.isclose() 사용.
  2. Decimal(0.1) 초기화: float 경유로 오염. 반드시 Decimal("0.1").
  3. 금융 계산에 float: 19.99 * 0.13 에서 센트 오차 발생. Decimal 필수.
  4. round(2.5) = 2: bankers’ rounding. 사사오입은 Decimal.quantize(ROUND_HALF_UP).
  5. NaN 비교: nan == nanFalse. math.isnan() 으로 확인.
  6. 루프 누적 오차: 반복 합산 시 math.fsum() 사용 권장.

관련 위키

이 글의 용어 (5개)
[Python] 연산자: 비교, 산술, 비트, 멤버십python
분류 | 종류 | 연산자 | 예시 | |------|--------|------| | 산술 | | , (행렬곱) | | 비교 | | | | 동일성 | | | | 멤버십 | | |…
[Python] collections: Counter, deque, defaultdict, OrderedDict, ChainMappython
정의 모듈은 dict/list/tuple/set의 특수화 컨테이너를 제공한다. 표준 라이브러리에 있는 데이터 구조 도구함의 핵심. | 클래스 | 용도 | |--------|---…
[Python] int: 임의 정밀도 정수python
정의 Python의 는 임의 정밀도 정수(arbitrary precision integer)다. C의 / 처럼 비트 폭이 고정되지 않으며, 메모리가 허용하는 한 무한히 큰 정수를…
[Python] random, statistics, mathpython
random: 의사 난수 은 Mersenne Twister 기반 PRNG. 통계·시뮬레이션·게임용. 보안엔 사용. 기본 함수 seed: 재현 가능 seed 없으면 OS의 rand…
수치해석 (Numerical Analysis)algorithm
정의 수치해석 (Numerical Analysis) 은 해석적 해가 어렵거나 없는 문제를 수치적 근사로 푸는 분야. PS 에서는 크게 두 가지가 자주 등장한다. Newton-Ra…

이 개념을 다룬 위키 페이지 (1)

💬 댓글

사이트 검색 / 명령어

검색

스크롤 = 확대/축소 · 드래그 = 이동 · 0 = 원래 크기 · ESC = 닫기