浮點數比較

2022-01-13 11:43:13 字數 1957 閱讀 1229

流言: 在實際使用中,使用不同的ε值來比較浮點數沒有什麼區別

正確性: 錯誤

通常當你在包含浮點數計算的任務的srm之後到round tables看看你會看到有人發出像「我把精度從1e-12改成1e-7就通過了practice room所有的系統測試」這樣的訊息。

這樣的討論的例子還有: here, here, here, here 和 here.(它們都是值得一讀的,從其他人的錯誤中學習要比從自己當中少痛苦一點)

我們將通過展示另外乙個簡單的例子來開始我們的解答。   

for(

doubler=

0.0; r

<

1e22; r

+=1.0

) printf(".

");這個程式將會列印多少個點呢?這次很清楚,不是嗎?這次的終止條件不再是等於測試。這個迴圈將會在10^22遍歷後停止。或者。。是嗎?

真糟糕,這又一次的成了死迴圈。為什麼會這樣呢?因為當r這個值變得大了,這個變數的精度並不能夠足夠大的儲存所有r的十進位制下的數。最後一些會丟失掉。因此當我們在這麼大的乙個數後加1,結果又被近似到原來的數了。

練習:試著判斷一下我們這個迴圈裡r所能達到的最大值。檢查你的答案,如果你的判斷出錯了,找出它的原因。

在作出觀察之後,我們將顯示為什麼表示式fabs(a-b)考慮值123456123456.1234588623046875和123456123456.1234741210937500。它們都沒什麼特別之處,僅僅是兩個double可以在不進行近似的情況下就能儲存的兩個值。他們直接的差大約在2e-5.

現知讓我們看看這兩個值的位形式:

first:  

01000010

00111100

10111110

10001110

11110010

01000000

00011111

10011011

second: 

01000010

00111100

10111110

10001110

11110010

01000000

00011111

10011100

是這樣的,沒錯。這是在double中可以被儲存的兩個連續的值。任何使用近似得到的錯誤都能夠使得其中對乙個變成另外乙個(或者超過)。但是他們仍然是不一樣的,因此我們原始的測試「相等」不能夠工作。

我們真正需要的是容忍一些小的精度誤差。正如我們所看到的,double能夠近似儲存最多15個10進製數字的數。通過近似積聚的精度錯誤,最後一些數字將會丟失。但是我們究竟應該怎樣容忍這些誤差呢?

我們將不使用固定常數ε,而使用乙個與比較的數數量級相關的值。更確切點說,如果x是乙個雙精度數,那麼x*1e-10是乙個比x小10倍數量級的數。它的最高有效位對應於x的第11位最高有效位。這使得它能夠很好的滿足我們的需要。

換句話說,乙個更好的方式來比較a,b兩個雙精度數是否「相等」就是檢查a是否在b*(1-1e-10)和b*(1+1e-10)之間。(小心,如果b是負數的時候,這兩個數中的第乙個將會更大!)

看到用這樣的比較方式的問題了嗎?試著比較1e-1072和-1e1072.這兩個數都機會相等並且等於0,但是我們的測試在處理這種情況時會失敗。這就是為什麼我們既需要做第乙個測試(測試絕對誤差)和第二個測試(測試相對誤差)。

這就是tc中用來檢查你的返回值是否正確的方法。現在你知道原因了。

有更好的比較函式(參見其中的一篇參考文章),但是更重要的是要知道在實際中你經常僅僅使用絕對誤差測試而僥倖成功。為什麼?

因為包含在計算當中的數字都是在限定的範圍之內。例如,如果我們需要比較的最大數只是9947,那麼你知道乙個double能夠在十進位制小數點後儲存另外的11個數字。因此我們在進行絕對誤差測試時使用epsilon=1e-8,我們執行最後的3個數字丟掉。

這個方法的優點很明確:檢查絕對誤差要比上面的高階測試簡單。

農夫三拳:

ps。看明白了沒,反正我是沒看明白。

浮點數比較

在數 算當中經常會涉及到判斷兩個數是否相等的情況 對於整數很好處理 a b這樣的乙個語句就可以解決全部的問題 但是對於浮點數是不同的 首先,浮點數在計算機當中的二進位制表達方式就決定了大多數浮點數都是無法精確的表達的 現在的計算機大部分都是數字計算機,不是模擬機,數字機的離散化的資料表示方法自然無法...

浮點數比較

部分 思路來自網路。fxxki整理發布。double變數以帶符號的 ieee 64 位 8 個位元組 雙精度浮點數形式儲存 它可以表示十進位制的15或16位有效數字.負值取值範圍為 1.79769313486231570e 308 到 4.94065645841246544e 324,正值取值範圍為...

浮點數比較

0 我們來看乙個程式 include int main else 1 執行結果 可以看出,我們輸入的2.3和計算出來的 4.6 2 相等,這個沒有問題。但是如果遇到下面這個問題 3 我們再來看一段程式 include include define eqs 1e 8 define equal a,b ...