2017-12-22 4 views
1

What is the most effective way for float and double comparison?에서 제안 된 것처럼 엡실론을 사용하는 복식의 비교 함수를 정의했습니다. 절대 값의 차이가 ε보다 작 으면 두 개의 double이 다릅니다.C++ 엡실론을 사용하는 복식의 비교

d2 = d1 + epsilon 인 d1과 d2를 두 배로 사용하면 d1은 ε만큼 다르기 때문에 d2는 d2와 같지 않아야합니다. 권리?

일부 값은 작동하지만 항상 작동하지는 않습니다. 아키텍처 나 컴파일러와 관련이있을 수 있습니까? 비교 기능을 개선하려면 어떻게해야합니까? 내 컴퓨터에

#include <iomanip> // For std::setprecision 
#include <iostream> 
#include "math.h" // For fabs 

const double epsilon = 0.001; 

bool equal(const double &d1, const double &d2) 
{ 
    return fabs(d1-d2) < epsilon; 
} 

int main() 
{ 
    double d1 = 3.5; 
    double d2 = d1+epsilon; 

    // d2 = d1 + epsilon should not be equal to d1. 
    std::cout << std::setprecision(16) << "d1 = " << d1 << " d2 = " << d2 << std::endl; 
    bool eq = equal(d1,d2); 
    if (eq) 
    { 
     std::cout << "They should not be equal, but they are!" << std::endl; 
    } 
    else 
    { 
     std::cout << "They are not equal. OK!" << std::endl; 
    } 
} 

출력 :

D1 = 3.5 (D2) = 3.501

그들은 동일하지 않아야하지만, 그들은있다!

+3

"나는 D2 =의 D1 + 엡실론과 복식 D1과 D2가있는 경우, D1은 엡실론 차이가 있기 때문에 D2 같아야 안된다. 그렇지?" 아니, 정확히 같은 이유로. – Slava

+0

부수적으로'std :: setprecision' 스트림 수정자는 내장 타입 정밀도를 수정하지 않습니다. 내장 유형 정밀도는 수정할 수 없습니다. – Ron

+6

아이러니가 보이지 않습니까? 부동 소수점 산술 연산이 부정확하다는 사실에 대처하기 위해 엡실론 비교를 사용하고 '엡실론'을 포함한 표현식에 대해 정확한 결과를 기대합니다. 'd1 + 엡실론'의 정확한 수학적 값은'double'에서 표현할 수 없으므로'd2'는 약간 작아집니다. –

답변

2

가장 자주 발생하는 부동 소수점 경고 중 하나 : 부동 소수점에 숫자를 입력해도 정확히 동일한 값으로 저장된다는 의미는 아닙니다. 대신, 의도 한 값에 가장 근접한 2 진 구조를 만들기 위해 약간 수정됩니다.

좋아, 다시 사업에!

std::cout << fabs(d1-d2) << std::endl; 

을 다음과 같은 :

0.0009999999999998899

보시다시피 출력을 찾을 : 소스 코드이를 추가하려고? 그것은 당신의 엡실론보다 분명히 적습니다.

+0

내가 때문에 엡실론 복식의 시스템 정밀도 (~ 1E-16)에 비해 (0.001)의 "큰"가치가 더 정밀 문제를 기대하지 않았다, 분명히 그 소망 적 사고였다. – Montplaisir

+0

이것은 시스템 정밀도와 관계 없습니다. 부동 소수점 숫자는 값을 인코딩하는 비트 양이 제한적입니다. 분명히 부동 소수점 값의 양은 셀 수없고 비트 조합의 양은 셀 수 있습니다. 따라서 모든 부동 소수점 형식 (float, double 등)은 손실 중심입니다. 그래서 생각해보십시오. 부동 소수점은 일종의 JPEG입니다 (어쨌든 저장소 기반 유물을 얻습니다). int는 PNG입니다. :) –

1

d2 = d1 + epsilon 인 경우 d1과 d2가 두 개인 경우 d1은 엡실론에 따라 다르므로 d2는 d2와 같지 않아야합니다. 권리?

틀린. 논리가 깨졌습니다. 당신은 엡실론없이 복식을 비교해서는 안된다고 말했지만 다음 단계는 fabs(d1-d2) == epsilon이 사실이 아니라고 놀랐습니다.

비교 기능을 개선하려면 어떻게해야합니까?

아무것도 d1 + epsilon 테두리 케이스이며, 그 수는 d1 여부를 동일한 경우 당신은 확신 할 수 없다. 그것은 부동 소수점 연산의 단점입니다.

0

여기에는 실제로 두 가지 문제가 있습니다. 첫째, 비교가> =가 아닌> =이어야하므로 차이가 정확히 엡실론 인 테스트 케이스에 "작동"합니다.

두 번째 (잠재적 인) 문제점은 이러한 종류의 비교에 대해 일반적으로 일정한 엡실론을 실제로 사용할 수 없다는 것입니다. 관련된 수의 예상 크기와 계산에서 예상되는 누적 숫자 오류를 기반으로 엡실론을 선택해야합니다.

부동 소수점 숫자가 정확하지 않으면 저장되는 값의 크기가 커집니다. "충분히 큰"값으로 테스트를 반복하면 매번 실패합니다.

0

하자 전화 pe 정밀 오류입니다. [의사 코드]

d1 = 3.5 + pe1 
d2 = 3.501 + pe2 

d2 - d1 = 0.001 + pe2 - pe1 

epsilon = 0.001 + pe3 

식의 결과 : [의사 코드]

|d1-d2| < epsilon //Since you know that d2>d1 you can replace |d1-d2| by d2-d1 
0.001 + pe2 - pe1 < 0.001 + pe3 
pe2 - pe1 < pe3 

이것은 수학이 binary64

표준 무한소 (~2^−53) IEEE 754 인 국경 경우 pe3, pe2pe1의 크기와 기호 true 또는 false dependig 될 수 있습니다. 그러나 그것은 불확실하다.