Creative Motive

double 타입 오차 허용 범위 내에서 비교하기 #2 본문

C++

double 타입 오차 허용 범위 내에서 비교하기 #2

aicosmos 2025. 5. 20. 21:11

출처 : 김경진님의 데브피아 (https://blog.naver.com/devmachine/220132178688)

 

오차 허용 범위 내에서 비교하기 - 상대 범위 사용

  

 

이번에 살펴볼 방법은 오차 허용 범위를 절대 범위로 사용하지 않고 상대 범위를 사용하여 비교하는 방법입니다. 여기서 상대 범위는 두 실수 값이 얼마의 비율(%)로 차이가 나는지를 의미하며, 상대 범위를 허용 가능한 오차 비율로 설정하여 비교하면 조금 더 유연하게 두 실수 값을 비교할 수 있습니다. 

 

int CompareDoubleRelative(double x, double y, double relTolerance = DBL_EPSILON)
{
    double diff = x - y;
    double lagest = max(fabs(x), fabs(y));

    if (fabs(diff) <= lagest * relTolerance)
        return 0;

    return (diff > 0) ? 1 : -1;
}

int main()
{
    double x = 123456789.03;
    double y = 123456789.1;

    x += 0.06;
    x += 0.01;

    if (0 == CompareDoubleRelative(x, y))
        printf("x == y\n");
    else
        printf("x != y\n");
}

 

 

 CompareDoubleRelative 함수의 세 번째 파라미터인 relTolerance는 오차 허용 상대 범위를 의미하며, 예를들어 0.00001을 전달하면 두 실수 값이 99.999% 일치했을 경우 같은 것으로 판단합니다. relTolerance 파라미터의 기본값은 DBL_EPSILON(2.2204460492503131e-016) 이며, 일반적인 상황에서는 기본값을 사용하면 잘 동작합니다.

 

하지만 안타깝게도 CompareDoubleRelative 함수가 지난번에 작성했던 CompareDoubleAbsoulte 의 단점을 완벽하게 보완할 수 있는 해결책은 아닙니다. CompareDoubleRelative 함수는 CompareDoubleAbsoulte 함수와는 반대로 0에 가까운 아주 작은 값을 기본 오차 허용 범위(DBL_EPSILON)를 이용하여 비교하면 제대로 동작하지 않을 수 있다는 단점이 남아있습니다.

 

 

오차 허용 범위 내에서 비교하기 - 절대 범위 + 상대 범위 사용

  

 

앞서 살펴본 CompareDoubleAbsoulte 함수와 CompareDoubleRelative 함수는 서로 상반된 단점을 한 가지씩 가지고 있습니다.  이러한 단점을 보완하여 조금 더 안정적인 비교 함수를 만들고 싶다면, 간단하게 두 함수를 조합하여 서로의 단점을 상쇄시킬 수 있습니다.

 

int CompareDoubleAbsoulteAndRelative(double x,
                                     double y,
                                     double absTolerance = (1.0e-8),
                                     double relTolerance = DBL_EPSILON)
{
    double diff = x - y;
    if (fabs(diff) <= absTolerance)
        return 0;

    double lagest = max(fabs(x), fabs(y));
    if (fabs(diff) <= lagest * relTolerance)
        return 0;

    return (diff > 0) ? 1 : -1;
}

 

CompareDoubleAbsoulteAndRelative 함수는 x - y의 절대값이 absTolerance 범위 내에 있거나, 두 값의 오차 비율이 relTolerance 범위 내에 있을 경우에 같은 것으로 판단합니다. 그러므로 비교하려는 값이 아주 크거나, 아주 작은 경우에도 문제 없이 사용할 수 있습니다. 

 

몇 단계에 거쳐 만들어진 CompareDoubleAbsoulteAndRelative 함수는 이제 충분히 쓸만해졌습니다. 하지만 여기서 마치지 않고 한가지 방법을 더 소개해드릴까 합니다. 바로 ULP(Unit in the last place)를 이용한 비교인데요, 지금까지의 구현 방법과는 전혀 다른 관점에서 접근하는 방법입니다. 이에 대한 자세한 내용은 다음 포스팅때 다루도록 하고, 오늘은 여기서 마무리하겠습니다.

 

Reference

  

 

Comparing floating point numbers - Bruce Dawson

Comparing Floating Point Numbers, 2012 Edition