앞서 정수형 자료형의 저장 구조와 2의 보수 표현 방식을 알아보았다. 이번 글에서는 소수점을 표현하는 실수형 자료형(float, double)의 내부 동작 원리인 부동 소수점(Floating Point) 체계와, 실수 연산 시 주의해야 할 정밀도 문제를 정리한다.
1. 정수와 실수의 데이터 처리 방식 차이
컴퓨터 메모리 관점에서 정수와 실수는 데이터를 저장하고 처리하는 방식이 완전히 다르다.
int a = 4; // 정수 표현 방식 (2진수로 직관적 저장)
float b = 4.0f; // 실수 표현 방식 (부동 소수점 체계로 저장)
-
정수형: 한정된 비트 공간 내에서 정확한 2진수 값으로 직관적으로 표현한다.
-
실수형: 과 사이에도 무한한 실수가 존재하기 때문에, 한정된 메모리 크기로 정확한 값을 담는 것은 불가능하다. 따라서 실수는 '정확한 값'이 아닌 '근사값'을 저장한다.
정수 4와 실수 4.0은 인간에게는 같은 수처럼 보이지만, 메모리에 저장되는 비트 패턴은 완전히 다르다.
2. 부동 소수점(Floating Point)이란?
컴퓨터는 IEEE 754 표준에 따라 실수를 지수부(Exponent)와 가수부(Mantissa)로 나누어 저장하는 부동 소수점 방식을 사용한다.
실수가 비트로 저장되는 정규화 과정 (예: 21.8125)
-
2진수 변환:
-
정규화(Normalization): 소수점을 이동시켜 맨 앞을 형태로 맞춘다.
-
비트 분배:
-
부호 비트 (Sign): 양수/음수 판별
-
지수부 (Exponent): 소수점의 위치 (의 )
-
가수부 (Mantissa): 소수점 뒤의 유효 숫자 영역 (
01011101)
-
3. 실수형 자료형의 종류와 정밀도
소수점 아래 자릿수가 길어질수록 가수부 비트 공간이 부족해진다. 따라서 더 큰 메모리를 사용하는 자료형일수록 더 높은 정밀도(Precision)를 가진다.
| 자료형 | 메모리 크기 | 유효 자릿수 (정밀도) | 비트 구성 (부호 / 지수 / 가수) |
|---|---|---|---|
| float | 4 바이트 (32 비트) | 소수점 이하 약 7자리 | |
| double | 8 바이트 (64 비트) | 소수점 이하 약 15~16자리 |
C/C++에서는 기본 실수 리터럴(예:
3.14)을double형으로 처리한다.float형으로 명시하려면 숫자 뒤에f리터럴 접미사를 붙여야 한다 (3.14f).
4. 실수 연산 시 주의할 점: 정밀도 문제와 오차 누적
부동 소수점 방식의 핵심은 "모든 실수를 정확하게 표현할 수 없다"는 점이다.
float f = 0.0f;
for (int i = 0; i < 100; i++) {
f += 0.1f; // 0.1을 100번 더함
}
// f의 실제 출력 결과: 10.000002 (정확히 10.0이 되지 않음)
조건문에서의 실수 비교 주의
실수 연산 시 미세한 오차가 발생하므로, 조건문에서 == 연산자로 실수를 직접 비교하면 예상치 못한 버그가 발생한다.
// ❌ 위험한 비교 방식
if (f == 10.0f) {
// 오차 때문에 거짓(False)이 될 가능성이 높음
}
// ⭕ 안전한 비교 방식 (오차 범위 내 비교)
if (fabs(f - 10.0f) < 0.00001f) {
// 두 값의 차이가 매우 작은 값(허용 오차) 미만인지 확인
}
5. 형변환(Casting)과 명시적 제어
정수와 실수가 혼합된 연산을 수행하면 컴퓨터는 둘 중 하나의 체계로 변환하는 암시적 형변환(Implicit Casting)을 거치게 되며, 이 과정에서 성능 하락이나 값 유실이 발생할 수 있다.
int a = 5;
int b = 2;
// ❌ 의도치 않은 소수점 절삭
float result1 = a / b; // 정수끼리의 연산(5 / 2 = 2)이 먼저 일어난 후 실수로 변환되어 2.0f가 됨
// ⭕ 명시적 형변환 (Explicit Casting)
float result2 = (float)a / b; // a를 실수로 강제 변환하여 2.5f라는 정확한 결과를 얻음
따라서 의도하지 않은 연산 오류를 방지하기 위해 가능하면 같은 자료형끼리 연산하고, 정수와 실수를 함께 사용할 때에는 명시적 형변환을 통해 개발자의 의도를 컴파일러에게 확실히 전달해야 한다.
마무리하며
- 정수는 '정확한 값', 실수는 '근사값'으로 처리된다.
- 실수 비교 시
==연산 대신 오차 범위(EPSILON)를 고려하여 비교해야 한다. - 혼합 연산 시 소수점 절삭 등의 오차를 막기 위해 명시적 형변환을 적극 활용하자.