3

我理解是這樣的:在C雙精度減去2個double數字時++它們首先轉化爲開始與一個次2到冪的一個有效數。那麼如果相減的數字在有效數字中具有相同的指數和許多相同的數字,則可以得到錯誤,從而導致精度的損失。爲了測試這個對我的代碼,我寫了下面的安全增加功能: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; 
} 

然而,測試此我注意到一些奇怪的事情:看來,實際的錯誤(不是函數是否報告錯誤,但是從實際的一個產生計算)似乎取決於減去數字的絕對值,而不是在尾數相同的數字只是數...

有關示例,使用1e-11的精度prec並減去以下號碼:

1)9.8989898989898-9.8989898989897:The函數報告錯誤,我得到了非常不正確的值9.9475983006414e-14

2)98989898989898-98989898989897:函數報告錯誤,但我得到正確的值1

顯然我誤解的東西。有任何想法嗎?

+0

如果您希望獲得的不僅是一個近似結果,而且是一個浮點計算錯誤的界限,您可以使用區間算術,向下舍入爲下限,向上舍入爲上限。必須有C++包才能做到這一點。 – 2013-04-29 20:40:02

回答

6

如果減去這幾乎是相等的兩個浮點值,結果將主要體現在低位噪音。這裏差不多相同的指數和幾乎相同的數字。例如,1.0001和1.0000幾乎相等,減去它們可能會被這樣的測試所捕獲。但1.0000和0.9999的差別完全相同,並且不會被像這樣的測試所捕獲。

而且,這是不是安全的新增功能。相反,這是對設計/編碼錯誤的事後檢查。如果你減去兩個非常接近的值,那麼噪音就會造成錯誤。修復錯誤。我不反對使用類似這樣的東西作爲調試幫助,但請將其稱爲暗示這就是它的意思,而不是暗示浮點加法存在固有的危險。此外,把除了函數內部的檢查似乎過度:斷言這兩個值不會造成問題,其次是一個普通的老浮點加法,可能會更好。畢竟,代碼中的大部分新增內容都不會導致問題,並且您最好知道問題所在的位置;在問題點上發表聲明。

+1

如果你寫了「如果你減去近似相等的兩個**近似值**浮點值,結果將主要反映低位噪聲」,那麼沒有人會狡辯。你寫的方式,有人可能會指出,減去兩個幾乎相等的浮點值是一個確切的操作(Sterbenz引理)。 – 2013-04-29 15:10:47

+0

@PascalCuoq - 我故意有點模糊,因爲這是寫給初學者,他不會從浮點數學的論文中受益。 – 2013-04-29 15:14:10

+0

@PeteBecker謝謝!我現在看到,我應該以某種方式使用數字的二進制值來完成此操作。你是否同意那麼測試會起作用,從那以後,有效數字總是從1開始的?對於名稱:你是對的,我想要的是一個用於查找代碼中的問題的工具;安全的補充是錯誤的選擇。 – jorgen 2013-04-29 15:21:55

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 2013-04-30 15:09:53

1

這很容易證明對於IEEE 754浮點運算,如果x/2 < = y < = 2x那麼計算x-y就是一個精確的運算,並且會給出準確的結果而沒有任何舍入誤差。

而且如果加法或減法的結果是非規格化數,那麼結果總是總是確切的。