[Python] float, Decimal, Fraction
python float, python decimal, python fraction, 부동소수점, 정밀 산술
정의
Python의 실수 산술은 세 가지 타입을 제공한다.
float: IEEE 754 double precision (64비트). Cdouble과 동일. 빠르지만 부정확.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.300000000000000040.1과 0.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/10Fraction(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
| 타입 | 상대 속도 | 정밀도 | 주요 용도 |
|---|---|---|---|
float | 1x (기준) | 53비트 이진 | 과학/ML/통계 |
Decimal | ~10x 느림 | 임의 정밀도 10진 | 금융/통화/회계 |
Fraction | ~30x 느림 | 완전 유리수 | 기호 수학 |
int | float 급 | 임의 정밀도 정수 | 정수 산술 |
부동소수 흔한 함정
WARNING
- 직접
==비교:0.1 + 0.2 == 0.3은False.math.isclose()사용. Decimal(0.1)초기화: float 경유로 오염. 반드시Decimal("0.1").- 금융 계산에 float:
19.99 * 0.13에서 센트 오차 발생.Decimal필수. round(2.5)= 2: bankers’ rounding. 사사오입은Decimal.quantize(ROUND_HALF_UP).- NaN 비교:
nan == nan은False.math.isnan()으로 확인. - 루프 누적 오차: 반복 합산 시
math.fsum()사용 권장.
관련 위키
- py-int (임의 정밀도 정수)
- py-operators (나눗셈 구분:
/vs//) - py-random-statistics (통계 계산)
- numerical-analysis (수치 해석 기초)
- py-collections (Counter 등 숫자 관련 컨테이너)
이 글의 용어 (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…
💬 댓글