2013-08-06 11 views
4

<,>,=,!= 연산자를 사용하여 C++에서 double 값을 비교할 때 우리는 항상 결과의 정확성에 대해 확신 할 수 없습니다. 우리가 다른 기술을 사용하여 doubles을 비교하는 이유는 예를 들어, 두 개의 a와 b를 비교할 수 있습니다. 그 차이가 실제로 0에 가까운 지 테스트 할 수 있습니다. 내 질문은 C++ 표준 라이브러리가 std::less<double>std::greater<double>을 구현하는 것인가 아니면 안전하지 않은 비교 연산자를 사용하는 것인가?std :: greater <double> 및 std :: less <double>은 안전한가요?

+1

"더 정확한"기술은'std :: set '과 호환되지 않습니다. 호환 가능하려면'a == b && a == c'는'b == c'를 의미해야합니다. – MSalters

+1

"차이가 실제로 0에 가까움"- 이것은 비교되는 값의 계산 문제를 해결하기 위해 작업 중입니다. 비교 자체에는 아무런 관련이 없습니다. 이는 잘 정의되고 정확합니다. 쓰레기 입력, 쓰레기 출력. –

답변

11

stl_function.h 헤더 파일에 더 큰 당신은 그 운영의 결과의 정확성에 대한 확인 100 %가 될 수 있습니다. double의 정밀도가 무한하지 않기 때문에 이전 계산에서 잘림이 발생했을 수도 있습니다. 따라서 연산자는 완벽하게 훌륭합니다. 피연산자가 예상 한 것과 다릅니다.

비교 대상으로 사용하는 것은 중요하지 않습니다. cppreference에서

+0

부동 소수점 결과는 일반적으로 반올림되거나 잘리지 않습니다. –

4

그들은 표준 연산자를 사용합니다. 여기에 표준의 정의는 ::

templatete<typename _Tp> 
    struct greater : public binary_function<_Tp, _Tp, bool> 
    { 
     bool 
     operator()(const _Tp& __x, const _Tp& __y) const 
     { return __x > __y; } 
    }; 
3

그것은

거기 않는 한 operator< 또는 operator> 특별히 적절한 비교를 구현하기 위해 double에 오버로드, 거기려고하고 있다는 것을 의미 T 형식

에 운영자 <를 사용 말한다 std::less 또는 std::greater을 사용하여 적절한 비교가 없어야합니다.

IOW 당신이 std::greater 또는 std::less을 사용할 수 있지만 일부 operator< 또는 operator> 특별히 double s 또는 float을 비교하기 위해 구현 이동하지 않는 한 표준 비교를 사용의 적절 미만 std::numeric_limits<double>::epsilon()

+1

음, "거의 같음"은 고급 기술입니다. 초보자에게는 적합하지 않으며 "적절한 비교"는 아닙니다. '<' and '>'와'=='는 적절한 비교를합니다; 결과와 관련된 모든 문제는 전달 된 값에서 나옵니다. 쓰레기 입력, 쓰레기 출력. –

+0

그리고 대략적인 비교가 적절했다하더라도 왜'std :: numeric_limits :: epsilon()'이 올바른 사용법이 될까요? 이는 1의 크기에서 표현 가능한 숫자 사이의 단계이지만 개별 연산의 반올림 오류는 1이 아닌 실제 결과의 크기에 따라 달라지며 여러 연산의 결합 오류는 일반적으로 어떤 방식 으로든 예측할 수 없습니다. –

4

operator<operator>가를 제공 할 자신의 차를 이용하여 정확한 결과를 적어도 가능한 한 멀리. 그러나 부동 소수점 연산, 특히 double 사용과 관련된 몇 가지 근본적인 문제가 있습니다. 현재 CPU에서 사용하는 부동 소수점 표현에 내재되어 있으므로 언급 한 비교 함수를 사용하여 이러한 값을 줄일 수 없습니다.

함수의 경우 std::less/std::greater : 이들은 STL 알고리즘에서 이진 조건자를 필요로 할 때 사용하기위한 표준 연산자의 패키지 된 버전입니다.

double 값은 64 비트 표현 인 반면 Intel CPU의 원래 "double"산술은 80 비트로 이루어집니다. "자유"에 대한 더 많은 정밀도를 얻으려면 처음에는 좋겠지 만 컴파일러가 FPU 레지스터 (80 비트) 또는 메모리에 다시 쓰여진 값에서 직접 중간 결과를 사용하도록 컴파일러에서 결정할 수 있는지 여부에 따라 달라집니다 (64 비트로 반올림 됨). 이러한 종류의 최적화는 완전히 컴파일러에 달려 있으며 어떤 표준에 의해서도 정의되지 않습니다.

현대적인 컴파일러는 상황을 더욱 복잡하게 만들기 위해 최신 벡터 명령어 (MMX/SSE)를 사용할 수도 있습니다.이 명령어는 다시 64 비트 전용입니다. 위에서 설명한 문제는이 문맥에서는 나타나지 않습니다. 그러나 부동 소수점 연산에 이러한 명령어를 사용하는지 여부는 컴파일러에 따라 다릅니다.

차이가 항상 가수의 마지막 비트에만있는 경우 거의 같지 않은 값에 대한 비교가 항상 어려워집니다.이 값은 항상 잘림 오류가 발생할 수 있으므로 프로그램이 비판적으로 의존하지 않도록해야합니다 매우 가까운 값의 비교 결과 예를 들어, 차이가 임계 값보다 작 으면 등호로 간주 할 수 있습니다 (예 : 에 의해 if (fabs(a - b)/a < factor*DBL_EPSILON) { /* EQUAL */ }. DBL_EPSILONfloat.h에 정의되어 있으며 factor은 가능한 절단/반올림이있는 수학 연산의 수에 따라 달라 지므로 철저히 테스트해야합니다. factor=16..32 주변의 값으로는 안전했지만 마일리지가 다를 수 있습니다.