포스트

[C++] 부동소수점 오차 및 비교 방법

[C++] 부동소수점 오차 및 비교 방법

C++ 부동소수점(Floating-Point) 오차 및 비교 방법

부동소수점은 실수를 컴퓨터 메모리에 저장하고 계산하는 방법입니다. 하지만 이 방식에는 고유한 한계와 오차가 존재합니다. 아래는 주요 개념, 예제, 그리고 실전에서 유의할 점들을 종합한 정리입니다.


1. 부동소수점이란?

  • 부동소수점(Floating-point)은 소수점이 고정되지 않고 떠다니는 방식으로, 값의 크기와 정밀도를 유연하게 표현할 수 있습니다.
  • 정수 또는 고정소수점 방식에 비해 더 넓은 범위의 수를 표현할 수 있지만, 정밀도 손실이 발생할 수 있습니다.

2. IEEE 754 표준

현대 컴퓨터에서 사용하는 부동소수점 표현 방식의 국제 표준입니다.

대표 형식

| 형식 | 비트 수 | 정밀도 (소수 자릿수) | |——|———|——————| | float (단정도) | 32비트 | 약 7자리 | | double (배정도) | 64비트 | 약 15~17자리 |


3. 부동소수점 오차 예제

3.1 < 0.1 + 0.2 ≠ 0.3 >

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
#include <iomanip>

int main() {
    double a = 0.1;
    double b = 0.2;
    double c = a + b;

    std::cout << std::fixed << std::setprecision(20);
    std::cout << "0.1 + 0.2 = " << c << std::endl;
    std::cout << "0.3       = " << 0.3 << std::endl;
    std::cout << std::boolalpha;
    std::cout << "Equal? " << (c == 0.3) << std::endl;
}

출력 예시:

1
2
3
0.1 + 0.2 = 0.30000000000000004441
0.3       = 0.29999999999999998890
Equal? false

3.2 누적 오차 예제

1
2
3
4
5
6
7
8
#include <iostream>
int main() {
    double sum = 0.0;
    for (int i = 0; i < 10; ++i) {
        sum += 0.1;
    }
    std::cout << (sum == 1.0) << std::endl; // false
}

4. 오차가 발생하는 이유

이진수 표현의 한계

  • 일부 십진수(예: 0.1, 0.2)는 이진수로 정확히 표현할 수 없어, 근사값만 저장됨
  • 예: 0.1(10진수)0.0001100110011...(2진수 무한 반복)

IEEE 754 구조 요약

  • float: 1비트 부호 + 8비트 지수 + 23비트 가수
  • double: 1비트 부호 + 11비트 지수 + 52비트 가수

5. C++에서 정밀하게 실수 비교하는 방법

실수끼리 비교할 때는 ==을 직접 사용하지 말고, 오차 허용 범위(Epsilon)를 고려해야 합니다.

절대 오차 기준

1
2
3
4
#include <cmath>
bool nearly_equal(double a, double b, double epsilon = 1e-9) {
    return std::fabs(a - b) < epsilon;
}

상대 오차까지 고려

1
2
3
4
#include <cmath>
bool almost_equal(double a, double b, double epsilon = 1e-9) {
    return std::fabs(a - b) <= epsilon * std::max(std::fabs(a), std::fabs(b));
}

C++17 이상: std::nextafter 활용

1
2
3
4
#include <cmath>
bool safe_equal(double a, double b) {
    return std::nextafter(a, b) == b;
}

6. 디버깅 팁

설명
setprecision(n)정밀 출력으로 오차 확인
디버거로 16진수 확인내부 표현을 직접 추적 가능
반복 연산 최소화누적 오차 방지 필요
문자열 비교 지양to_string() 결과는 정확하지 않음

8. 요약 정리

항목설명
Floating-point유연하고 광범위한 실수 표현 방식
IEEE 754부동소수점 표현 표준 (float, double 포함)
비교 방식== 대신 오차(Epsilon) 기반 비교 권장
디버깅setprecision, isnan, 반복 합산 시 유의
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.