想到的一個辦法是abs(num)&<10e-8;


0就是0。如果num == 0.0為假,那麼num就不為0.

你說的這個是處理實際數據時候的誤差問題。這和C++或者編程無關,任何數據處理,在存在誤差的前提下,絕大多數情況都只能判斷兩個結果是否足夠接近,而不能直接判斷相等。

而具體多大範圍內可以視為「足夠接近」。這取決於你數據原本的測量或者記錄的誤差、你的具體運算過程、以及你需要的精度。不是隨便拿一個你覺得很小的數就可以的。


一般情況,題主的方法已經能湊合了(即再一個很小範圍內的數作為0)。浮點數是不精確的,應當實際情況實際考慮。我不知道題主希望的是完全精確地為0(+/- 0.0000000....0f),還是想表示我想像中的為0(例如覺得(x / y) * y - x的結果一定是0的這種為0,即數學上來說,它應該等於0)。

精確比較,num == 0.0

很多人不推薦這種寫法,但是事實上這是保證num確確實實等於0(包括+0.0和-0.0)的判斷寫法,我們配合一個可以被float精確表示的數:

0.0078125 * 1000當然是7.8125,所以差值是0

可以看到,我們拿到了令人喜歡的結果。這是因為浮點數的加減乘除是精確舍入(據傳言是0.5ulp,非常精確,在遵循IEEE 754/854的機器上是這樣的(暗示曾經有那種a + b都不精確的語言/機器存在過))的。下面引入一個超越函數來帶來誤差:

此時,特點就明顯了——sin運算引入的誤差累計導致了結果並不是0,儘管從程序上看,結果本應該是0來著

看起來差不多,fabs(num - constant) &< constant_value

例如判斷a是否0fabs(num - 0.0) &< constant_value。但是這個方案提出的問題和它解決的問題一樣多——constant_value是多少?機器ε嗎?1e-6嗎?1e-8嗎?可見這也不是一個完美方案。同時,這樣的寫法並不保證num是真正的0,而是它大致上為0。到底該小於幾的問題很快就可以凸顯出來:


選擇哪一種,應當由題主自行決定。當然,這種寫法:fabs(a - b) &< DBL_EPSILON、&< 1e-8並不是萬能的。所以一定要實際情況實際考慮,並且儘可能的避免誤差的引入

什麼叫儘可能的減少誤差,舉個栗子,複數除法:

[公式]

這個公式上過高中的你應該是非常非常熟悉。直覺,很顯然,分母 [公式] 太大的話運算誤差就會上天。所以我們要避免分母太大來減少誤差。例如變成這樣(傳言中是Smith的公式,哪個Smith我就不知道了hhhhhh):

[公式]

想辦法去保證它儘可能的在安全範圍內,這就是減少誤差的操作。類似的例子還有很多,例如浮點數組求和、計算ln(1 + x)、已知三邊算三角形面積、一元二次方程求解等等。它們都會存在至少一種可能遇到的特殊情況導致誤差變大。對於任何浮點計算,都應該去考慮怎麼避免誤差


浮點數為0就是 a == 0;

如果不等, 那麼a就不是0

你的寫法是指近似為0, 而不是0


上一個Qt的實現吧

*/
static inline bool qFuzzyIsNull(double d)
{
return qAbs(d) &<= 0.000000000001; } /*! internal */ static inline bool qFuzzyIsNull(float f) { return qAbs(f) &<= 0.00001f; }


浮點數裡面本來就有0這個值啊??

我覺得你是想解決演算法用浮點數計算產生誤差的問題吧?


推薦閱讀:
相關文章