4

比方說,我們已經聲明瞭以下變量在C++中進行數學運算時,浮點錯誤是如何傳播的?

float a = 1.2291;

float b = 3.99;

float變量具有精度6,這(如果我理解正確)表示數之間的差異,計算機實際存儲並且你想要的實際數量將小於10^-6

這意味着ab都有一些誤差小於10^-6

所以電腦a裏面實際上可能1.229100000012123b可能是3.9900000191919

現在讓我們假設你有下面的代碼

float c = 0; 
for(int i = 0; i < 1000; i++) 
     c += a + b; 

我的問題是,

c的最終結果的精度誤差小於10^-6作爲w還是不是?

如果答案是否定的,我們如何才能真正知道這個精度錯誤,以及如果您應用任何類型的操作(如您希望的次數和順序),究竟發生了什麼?

+6

閱讀它,它會回答你所有的問題和更多:http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html – avakar 2014-09-06 21:07:00

+0

該文章似乎翔實,我會研究它,因爲浮動點錯誤讓我很頭痛,謝謝! – ksm001 2014-09-06 21:14:11

+0

您對精度的定義不正確。六位十進制數字的精度意味着該數字將精確到許多數字,而不會超過其數量級別。 – EJP 2014-09-06 21:31:44

回答

5

浮動變量具有精度6,其(如果我理解正確)表示的數量之間的差要將是計算機實際商店和實際數量小於10^-6

這意味着A和b兩者有一些誤差小於10^-6

的10 -6圖是相對精度的粗略測量表示任意常數爲浮點數時。不是所有的數字都會以絕對誤差10 -6表示。例如,編號爲8765432.1的預計可以近似地表示爲單位。如果你至少有一點幸運,那麼當你將其表示爲float時,你會得到8765432。另一方面,1E-15f可以預計以至多約10的絕對誤差來表示。

使電腦內部的實際上可能是1.229100000012123和B可能是3.9900000191919

沒有,對不起,它的工作方式是不是你寫的整個數字並添加六個零爲可能出現的錯誤。可以通過從前導數字而不是從最後一位數字計算六個零來估計該誤差。在這裏,您可以預期1.22910012123或3.990000191919。

(其實你也會得到完全相同1.2290999889373779296875和3.9900000095367431640625。不要忘了,表示錯誤可能是負的,以及積極的,因爲它是第一個數字。)

現在讓我們說,你有下面的代碼[...]

我的問題是,

c的最終結果具有精度誤差小於10^-6還有沒有?

號總絕對誤差將所有的錯誤,表示爲ab爲每個使用過一千次的總和,再加上你做了2000和增補的錯誤。這是4000種不同的錯誤來源!它們中的許多將是相同的,它們中的一些將恰好相互補償,但最終結果可能不是相對準確性,更像是相對準確性(建議不計算)。

3

這是一個非常好的問題,一個已經被許多權威人士解決了幾十年的問題,本身就是一個計算機科學學科(for example)。從What Every Computer Scientist Should Know About Floating-Point Arithmetic

浮點運算被認爲是受到很多人的一個深奧的主題。這是相當令人驚訝的,因爲浮點在計算機系統中無處不在。幾乎每種語言都有一個浮點數據類型;從PC到超級計算機的計算機都有浮點加速器;大多數編譯器會被要求不時地編譯浮點算法;幾乎每個操作系統都必須響應浮點異常,例如溢出。本文提供了一個關於浮點的方面的教程,這些方面對計算機系統的設計者有直接的影響。它以浮點表示的背景和四捨五入錯誤開頭,繼續討論IEEE浮點標準,並結合大量計算機構建者如何更好地支持浮點的例子。

(重點煤礦)

+1

「每個計算機科學家應該知道的浮點算術」幾乎都不是關於數值分析,這正如你正確地指出一門學科本身,並且將任何計算機浮點標準早於3000年,如果維基百科是相信的:http://en.wikipedia.org/wiki/Numerical_analysis – 2014-09-06 23:25:57

+0

你提供的另一個參考文獻,http://www.csee.wvu.edu/swarch/SARATool/docs/Error_Propagation_in_SW_Arch_Final.pdf,是關於在**分佈式系統中傳播**失敗**。除了在標題中有「錯誤」和「傳播」兩個字之外,與手頭主題沒有任何關係。 – 2014-09-06 23:48:19

-2

簡短的回答是,你可以很容易地確定浮點運算的長鏈的精度。

"c += a + b"這樣的操作的精度不僅取決於浮點實現(現在幾乎總是IEEE)的原始精度,而且取決於a,b和c的實際值。

繼,編譯器可以選擇,以優化以不同的方式,這會導致意外的問題的代碼,例如將其轉化爲"c+=a; c+=b;"或簡單地執行環路"tmp = a*1000; tmp += b*1000; c += tmp;"或一些其它變型中,編譯器會決定導致更快的執行時間但結果相同。

底線是僅通過檢查源代碼就無法分析精度。

由於這個原因,許多隻是使用更高精度的實現,如double或long-double,然後檢查精度問題是否出於所有實際目的。

如果這還不夠,那麼後退總是以整數實現所有邏輯並避免浮動。

+5

像你所描述的轉換(['a +(b + c) - >(a + b)+ c'](http://gcc.gnu.org/wiki/FloatingPointMath#Transformations))只允許if你使用快速浮點優化進行編譯,也就是說,當你在正常的浮點模式下編譯時,不允許編譯器按照浮點運算的順序進行調整(對於GCC和MSVC來說,這是真的) – BeyelerStudios 2014-09-06 21:51:01

+4

你的「後退」選項幾乎總是使所有的東西變得更糟。 – tmyklebu 2014-09-06 22:30:39

+0

在非常具體的情況下,定點算術可能是正確的選擇。金錢是一個體面的例子 - 你有一個不可分割的'原子',比如說便士,它比標準單位少,但*不*按2的冪。在Bash中快速:'echo $((0.10))' - > 0.10000000000000001。定點解決這個問題 - 僅以便士來處理。一般來說,您正在與IEEE及其所有邊緣案例競爭,以實現同樣的錯誤。 (FYI,同樣的方法:$((0.1 + $((0.2-0.2)))) - > 0.10 ... 1,'$(($((0.1 + 0.2)) - 0.2))' - > 0.10 ... 3。)[關於快速浮動](https://stackoverflow.com/a/16069874/1043529) – 2017-10-27 12:35:53