3

내가 이해하는 방식은 다음과 같습니다. double 두 자리를 C++에서 배정 밀도로 뺄 때 첫 번째는 지수의 거듭 제곱으로 시작하는 significand로 변환됩니다. 그런 다음 빼기 된 숫자가 동일한 지수와 유효 숫자의 동일한 자릿수가 많으면 정밀도가 떨어질 수 있으므로 오류가 발생할 수 있습니다. 내가 뭔가 이상한 알이 테스트, 그러나C++ 부동 소수점 빼기 오류 및 절대 값

double Sadd(double d1, double d2, int& report, double prec) { 
    int exp1, exp2; 
    double man1=frexp(d1, &exp1), man2=frexp(d2, &exp2); 
    if(d1*d2<0) { 
     if(exp1==exp2) { 
      if(abs(man1+man2)<prec) { 
       cout << "Floating point error" << endl; 
       report=0; 
      } 
     } 
    } 
    return d1+d2; 
} 

: 내 코드를 테스트하려면 나는 다음과 같은 안전한 추가 기능을 썼다가 보인다 실제 오류 (하지 기능이 오류를보고하지만 실제 하나가 인한 여부

: 계산) 다음 번호를 정밀도 prec1e-11를 사용하여 감산, 예를 들어

... 감산 번호의 절대 값이 아니라, 유효 동등한 숫자의 단지 수에 의존하는 것으로 보인다 1) 9.8989898989898-9.8989898989897 : 함수는 에러를보고하고 나는 매우 잘못된 값이 9.9475983006414e-14

2) 98989898989898-98989898989897 얻을 :이 기능은 오류를보고 있지만 정확한 값 1

에게 분명히 내가 잘못 이해 한 무언가를 얻을. 어떤 아이디어?

+0

근사 결과뿐만 아니라 부동 소수점 계산의 오류에 대한 경계를 얻으려면 간격 산술을 사용할 수 있습니다. 하한은 아래쪽으로 반올림하고 상한은 위쪽으로 반올림됩니다. 쉽게 사용할 수있는 C++ 패키지가 있어야합니다. –

답변

6

거의 같은 두 부동 소수점 값을 빼면 결과는 대부분 낮은 비트의 노이즈를 반영합니다. 거의 동등한 지수와 거의 같은 숫자입니다. 예를 들어, 1.0001과 1.0000은 거의 동일하며, 이들을 빼는 것은 이와 같은 테스트에 의해 포착 될 수 있습니다. 그러나 1.0000과 0.9999는 정확히 같은 양만큼 다르며 이와 같은 테스트에서는 발견되지 않습니다.

또한, 이것은 이 아니고,이 안전한 부가 기능이다. 오히려 설계/코딩 오류에 대한 사후 점검입니다. 너무 가까워서 노이즈가 중요한 두 값을 빼면 실수를 저 지르게됩니다. 실수를 수정하십시오. 나는 디버깅 보조 도구로 이것을 사용하는 것에 반대하지는 않지만, 부동 소수점 추가에 대해 본질적으로 위험한 것을 제안하는 것보다는 그것이 무엇인지를 나타내는 무언가라고 부릅시다. 게다가, 체크를 덧셈 함수 안에 두는 것은 과도한 것처럼 보입니다 : 두 값이 문제를 일으키지 않을 것이라는 주장, 보통 오래된 부동 소수점 덧셈이 더 좋을 것입니다. 결국 코드에 추가 된 대부분의 부분이 문제가되지 않으며 문제가있는 부분을 잘 알아야합니다. 문제 지점에 주장을 넣으십시오.

+1

"거의 비슷한 두 개의 ** 근사치 ** 부동 소수점 값을 뺀 경우 그 결과는 대부분 낮은 비트의 노이즈를 반영합니다."그러면 아무도 말을 꺼려하지 않을 것입니다. 당신이 그것을 작성한 방식으로, 누군가는 거의 동일한 두 부동 소수점 값의 빼기가 정확한 연산 (Sterbenz 보조 정리)이라는 것을 지적 할 수 있습니다. –

+0

@ PascalCuoq - 의도적으로 약간 퍼지기는했는데, 이는 부동 소수점 수학에 대한 논문으로 도움이되지 않는 초보자를 위해 작성 되었기 때문입니다. –

+0

@PeteBecker 감사합니다! 이제 숫자 대신 이진수 값을 사용하여이 작업을 수행해야합니다. 그 다음에 유효성 검사는 항상 1부터 시작하기 때문에 테스트가 작동한다는 것에 동의하십니까? 이름을 위해 : 내가 원하는 것은 코드에서 문제를 찾는 도구입니다. 안전한 추가는 잘못된 단어 선택이었습니다. – jorgen

2

+1 피터 베커의 대답. 예를 들어,

1.0-0.99999999999999 

그래서,

bool degenerated = 
     (epx1==exp2 && abs(d1+d2)<prec) 
    || (epx1==exp2-1 && abs(d1+2*d2)<prec) 
    || (epx1==exp2+1 && abs(2*d1+d2)<prec); 

당신은 검사를 생략 할 수 있습니다 빼기 경우

퇴화 결과의 문제가 아니라! EXP1 발생할 수 있음을

주 = EXP2 d1 * d2 < 0 일 경우, 그렇지 않으면 전체 테스트를 피하십시오.

축약 된 비정규 화 된 부동 소수점을 사용하여 정밀도 손실을 처리하려는 경우에는 소수점 이하가있는 소수점 이하 부동 소수점 수를 계산할 수 있습니다.

+0

알았어! 그래, d1 * d2가 있기 때문에 복잡한 코드로 표지판을 알아야 할 필요는 없지만 모든 것을 다르게 피할 수 있도록 시작 부분에 넣어야합니다. – jorgen

1

IEEE 754 부동 소수점 연산의 경우 x/2가 < = y < = 2x이면 x - y를 계산하는 것이 정확한 연산이며 반올림 오류없이 정확하게 결과를 제공한다는 것을 증명하는 것은 쉽습니다.

그리고 더하기 또는 빼기 결과가 비정규 숫자 인 경우 결과는 항상 exact입니다.