使用 epsilon 比較浮點數是否不夠科學?

時間 2021-05-31 05:34:17

1樓:

感覺基本都是從理論角度分析的,我來從ISA和硬體實現的角度簡單說一下吧

1, 常用函式的數值演算法,基本不是級數展開+區間擬合,就是構建在sqrt,log2,exp2等等基本函式之上,而這些基本函式不論軟硬體實現也仍然是級數展開。既然是擬合,那自然不能強求完全bitexact的結果。只能要求最終返回的浮點數值和「無限精確」的結果之間的差值小於一定限度。

這是來自演算法的誤差

2,即使某些函式可以用精確的公式計算,但是用到的超越數常數, 和e這些,是沒法用浮點數精確表示的。你的常數不准,那麼最後算出來的結果也一定有誤差,所以只能規定乙個誤差上限。這是IEEE754的限制

3,即使你的演算法裡用不到超越數,而且數學上不需要任何近似演算法,只有基本的+-*/運算,但是ALU的輸出精度是有限制的。兩個FP32的乘法一定會有46位基數,兩個數量級有差的數加減一定會產生基數溢位。但是輸出只有23位基數。

往上靠(RTP)還是往下靠(RTN)還是交替往上往下靠(RTE)?無論哪一種選擇,都會在每一條新的ALU指令之後引入新的誤差---除非你做的是乘以2這種不改變基數的運算。這是來自IEEE754下運算器實現的誤差

大部分程式語言的SPEC裡,採用ULP(Unit in Last Place)和絕對誤差相結合的方式,規定了重要函式的精度要求。

2樓:Anonymous

boost有乙個有理數類,boost::rational,可以不損失精度地進行有理數運算。當然,用來做大量圖形學計算是不現實的,會產生超級大的整型的分子和分母。

可能有的情景下,需要用到的是有理數類而不是浮點數類。

3樓:高天

浮點數本來就是乙個數學工具,拿來做重要的邏輯運算當然是不合適的。重要的底層軟體裡是不會出現浮點數的,都是整形。

從另乙個角度說,如果你要解決乙個數學問題,浮點數當然不是不能用,比如迭代乙個不算太精確的pi啊,隨機演算法算個概率啊之類的。

關鍵的是要知道你想做什麼,浮點數有他好用的地方,也有他有瓶頸的地方。說出現浮點數或者epsilon一定錯有些矯枉過正了。

如果要深究到底浮點數應該怎麼做才會更正確,就要先去學一下浮點數是如何表示的,IEEE standard的32bit浮點數裡有1位sign,8位exponent,23位mantissa,也就是說表示任何乙個數的精度大概是1/2^23。換言之,你舉的例子很對,對於不同大小的數用同樣的epsilon是不對的。而你提到的1e-6,簡單解釋一下就是,FLT_EPSILON大概是1.

19e-7,也就是1/2^23,也就是浮點數可以表達的最小的使得1+FLT_EPSILON != 1的數。而1e-6大概比這個多乙個數量級,也就是大約3個bit。

就是針對1附近的運算,允許3個bit的誤差。很多人提到了做乙個除法求相對值,就是把結果拉到1附近。

做一點點除法的分析吧,假設兩個數a和b在同乙個數量級且a>=b,誤差分別為a×f,b×f,其中f為FLT_EPSILON。換句話說a, b企圖表達的準確值只被浮點數的表達能力影響。這時候a, b企圖表達的準確值分別是a(1-f)~a(1+f)和b(1-f)~b(1+f)之間的數。

兩個數相除我們得到的浮點數是(a/b)(1-f)~(1/b)(1+f),而準確值最大誤差是(a/b)(1+f)/(1-f)~=a/b(1+2f)。可見這個除法導致了兩件事:

1、當a,b在同乙個數量級的時候,把誤差帶到了f的數量級,這時候用FLT_EPSILON的數倍就變得更有意義,比如1e-6。

2、除法本身導致了誤差增加,結果誤差不再僅僅是表達誤差,而引入了計算誤差。換句話說兩個不准的數,除了一下變得更不准了。而正是這種浮點數的累積誤差使得我們在需要非常嚴密邏輯的時候,對浮點數敬而遠之。

擴充套件一下,你說的abs(4e10 - 4.0000004e10) < 1e-6和4e10 == 4.0000004e10是完全等價的,因為4e10的精度到不了那麼高。

4樓:dyntkj

#include

/* FLT_EPSILON */

#include

/* fabs() */

floatf1,

f2;if(

fabs(f1

-f2)/

f1

)else

為什麼叫浮點數

道不輕傳 定點數能表示的數字有限,因為小數點固定,整數字和小數字就固定,就不利於表達特別大或特別小的數,浮點數就可以表示很大或很小的數字,因為小數點不固定,比如 123.45 用十進位制科學計數法可以表達為 1.2345 10 其中 1.2345 為尾數,10 為基數,2 為指數。浮點數利用指數達到...

浮點數是如何計算hash的?

hash的本質是對二進位制串進行操作,只要有一位不同hash結果就差千萬里。那麼,你的問題就是先把相近的值用相同的二進位制串表達,然後去計算hash。具體怎麼定義相近,就由你自己實現。最簡單的辦法就是用吧。這裡的公式編輯器不支援分數麼? 如何保證被看做相等的兩個數值非常接近的浮點數hash到相同的值...

浮點數如何轉換為定點數?

Aman 按 IEEE754 標準,float 的格式是 binary32,double 的格式是 binary64,浮點數中的有效數字 significant 部分其實可以理解為是乙個定點數,只不過有指數 exponent 部分做了小數點偏移 類似科學計數法,只不過是二進位制的,浮點數因此得名 我...