2012-01-25 6 views
1

다음은 허용 오차 내에서 2 개의 double 값의 동등성을 결정하기위한 코드의 테스트 블록입니다.숫자 비교에 영향을 미치는 이중 입도 C++

double lhs_1 = 0.02; 
double lhs_2 = 0.04; 
double rhs = 0.03; 
double tolerance = 0.01; 

bool is_match_1 = (abs(lhs_1 - rhs) <= tolerance); 
bool is_match_2 = (abs(lhs_2 - rhs) <= tolerance); 

그러나 is_match_2는 false로 밝혀졌습니다. 나는 컴퓨터에 저장된 숫자가 신중한 값이며 연속적이지 않다는 것을 알고 있습니다. 누군가가 해결책을 공유 할 수 있습니까? 나는 이유 안에서 시험을 통과하는 측면에서 잘못하고 싶습니다. 현재 어떤 정밀도 (double의 비트 레이아웃에 익숙하지 않다)에 대해 double 값을 1 씩 증가시키는 방법이 있습니까? 왜냐하면이 세분성 문제를 허용하기 위해 허용치를 증가시킬 수 있기 때문입니다.

편집 :이 정말 입력 및 허용 오차를 정의하는 사용자를 구현, 그래서 난 그냥 그들에게 입력 어떤 값에 대한 예상 출력을 제공하기 위해 노력하고있어

.

+0

단위 테스트 라이브러리는 누구입니까? http://stackoverflow.com/questions/17333/most-effective-way-for-float-and-double-comparison –

+0

사용 하시겠습니까? googletest와 같은 대부분의 패키지에는 표준 EXPECT_EQ()에 대한 EXPECT_DOUBLE_EQ()가 있습니다.이 패키지는 사용자를 대신하여이 패키지를 처리합니다. – kfmfe04

+0

http://stackoverflow.com/questions/1245870/next-higher-lower-ieee-double-precision-number 다음 가장 큰 배를 찾는 법을 설명합니다. 이것이 아마도 관용에 유용하지는 않을 것이다. 몇 가지 계산을 수행하면 오류가 이보다 커질 수 있습니다. – arx

답변

2

불행히도 허용 오차를 선택하기위한 "좋은"규칙은 없습니다. 귀하의 처분에 당신은이

하나에 추가, 가장 작은 값입니다 "기계 엡실론"

double epsilon = std::numeric_limits<double>::epsilon() 

는 것과 다른 결과를 제공합니다.

나는 보통 엡실론의 기능으로 내 공차를 씁니다. 좋은 규칙은 없지만, 예를 들어 이와 같이 비교하면

bool fuzzy_equals(double a, double b) 
{ 
    static const double eps = std::numeric_limits<double>::epsilon(); 
    return std::fabs(b - a) < 1024 * eps * std::max(a, b); 
} 

이 많은 경우에 잘 작동합니다. 당신은 1024를 조정할 수 있습니다, 나는 2의 힘을 좋아하지만, 그렇지 않을 수도 있습니다. 선택하는 실제 값은 문제에 따라 다릅니다. 복식에 대한 엡실론은 약 10^-16이므로 1024가 상당히 작기 때문에 많은 경우에 더 많은 수를 필요로합니다. (실질적으로 모든 조작, fuzzy_equals 내에서의 마이너스 연산 포함)은 엡실론을 "먹습니다"- 취소 할 수 있습니다 평균적으로 n 연산은 sqrt(n) * epsilon의 정밀도를 의미하므로 1024는 100 만 연산 이후의 예상 정밀도에 해당합니다).(최소치는 보통 (EPS) 정확도 SQRT하도록 결정된다), I는

bool fuzzy_equals2(double a, double b) 
{ 
    static const double eps = std::numeric_limits<double>::epsilon(); 
    return std::fabs(b - a) < 1024 * std::sqrt(eps) * std::max(a, b); 
} 
를 사용하여 공지 된 값에 대해 함수의 최소값을 테스트 할 때 정밀도가 예를 들어, 같은 좋지 않은 다른 경우들에서,

나는 종종 std::pow(eps, something) 또는 심지어 -1/std::log(eps)과 같은 다른 기능을 사용합니다. 이것은 어떤 문제에서 파생 될 수있는 이전 정보에 따라 달라지며 어떤 오류입니까? 입니다.

코드 구조에 관해서는 기능적 접근 방식을 사용하고 비교 자을 내 알고리즘에 전달합니다. STL 조건부와 비슷합니다. 이렇게하면 알고리즘 비교 논리를 하드 코딩 할 필요가 없습니다.

간략히 말하자면, 하나의 크기에 맞는 규칙은 없습니다. 문제에 따라 선택해야합니다.

0

일부 도움이 될 수있는 내성을 갖는 요점은 간단 평등 검사를 피할 수있다. 당신은 방금 어려운 방법을 배웠으므로 두 배로는 실제로 작동하지 않습니다. 복식 세계에서 1 + 1은 2와 같지 않을 수 있습니다 (내부적으로는 1.99999743과 같을 수 있음).

"차이 같음 허용 오차"는 신뢰할 수있는 조건이 아닙니다. 허용 오차는 예상 오차 인과 동일한 값인 과는 달리 값 사이의 현명한 차이보다 1-2 배 작아야합니다. 그래서 당신은 lhs_2 경우 싶어 체크하는 경우 - 우는 우 같다 - 허용 오차 내에서 lhs_1, 다음과 같은 검사가 더 나은 서비스를 제공합니다 :

fabs((lhs_2 - rhs) - (rhs - lhs_1)) < 0.0001 
+0

1 + 1은 항상 정확히 2와 같을 것입니다. 그러나 0.1은 종종 정확하지 않습니다. –

+0

여기에 원유 예제로 지시하기 :) 그것은 하나의 관심을 끌기에 완벽하게 좋은 기술입니다 :) –

0

귀하의 허용 오차가 이미 매우 느슨한 - 0.01 당신이있어 숫자에 비해 거대하다 비교. 최대 0.01000001까지 열면 괜찮을 것입니다.