2010-05-26 172 views
3

可能重複:
Floating point inaccuracy examplesC++浮點精度

double a = 0.3; 
std::cout.precision(20); 
std::cout << a << std::endl; 

結果:0.2999999999999999889

double a, b; 
a = 0.3; 
b = 0; 
for (char i = 1; i <= 50; i++) { 
    b = b + a; 
}; 
std::cout.precision(20); 
std::cout << b << std::endl; 

結果:15.000000000000014211

所以..'a'比它應該小。 但是,如果我們採取'一個'50次 - 結果會比它應該更大。

這是爲什麼? 如何在這種情況下獲得正確的結果?

+4

去看看吧。浮點問題需要仔細研究,以免發生危險錯誤。 – Artelius 2010-05-26 00:26:12

+0

有精確的值使用整數來代替(或一些bignum lib)const int acc = 100; int tmp,a = 30/acc,b = 0; for(char i = 1; i <= 50; i ++)b = b + a; std :: cout << int(b/acc)<<「。」; TMP = B%ACC; if(tmp <10)std :: cout <<「0」; std :: cout << int(tmp);爲了加快速度,你可以使用2的冪乘以所以*,/,%轉換爲<<,>>和 – Spektre 2013-08-20 13:07:12

回答

14

爲了得到正確的結果,不要設置的精度大於此數字類型的可用範圍:

#include <iostream> 
#include <limits> 
int main() 
{ 
     double a = 0.3; 
     std::cout.precision(std::numeric_limits<double>::digits10); 
     std::cout << a << std::endl; 
     double b = 0; 
     for (char i = 1; i <= 50; i++) { 
        b = b + a; 
     }; 
     std::cout.precision(std::numeric_limits<double>::digits10); 
     std::cout << b << std::endl; 
} 

儘管如果該循環運行5000次迭代而不是50次,即使採用這種方法,累積的錯誤也會顯示 - 這只是浮點數的工作原理。

+4

對於numeric_limits,+1確切地說是不夠的,因爲它們應該是。 – 2010-05-26 00:47:47

5

計算機以二進制形式存儲浮點數,而不是十進制。

在十進制中看起來很普通的很多數字,例如0.3,在二進制中沒有精確的有限長度表示。
因此,編譯器會選取具有精確二進制表示的最接近的數字,就像您爲1⁄3編寫0.33333一樣。

如果添加了許多浮點數,這些微小的差異加起來就會得到意想不到的結果。

+2

我認爲OP的關鍵答案是「你無法使用浮點得到正確的結果」。 :) – 2010-05-26 01:20:51

+3

你會得到正確的結果。可以肯定的是,不是你期待的結果。 – MSalters 2010-05-26 07:15:07

1

這並不是說它變得更大或更小,它只是在一個二進制浮點數內存儲「0.3」作爲一個確切值是不可能的。

獲得「正確」結果的方法是不顯示20位小數。

+0

0.3或0.3333 ....? – 2016-04-26 12:50:10

8

這是爲什麼?

因爲浮點數以二進制形式存儲,其中0.3是0.01001100110011001 ...重複就像1/3是0.333333 ...一樣以十進制重複。當你寫0.3時,你實際上得到了0.299999999999999988897769753748434595763683319091796875(將無限的二進制表示四捨五入爲53位有效數字)。

請記住,對於設計了浮點的應用程序,這不是一個問題,您無法準確表示0.3。浮點被設計爲用於:

  • 物理測量,這往往是測量到只有4 SIG無花果和從未超過15
  • 超越功能,如對數和三角函數,這無論如何只是近似。

對於哪些二進制十進制轉換與其他錯誤來源幾乎無關。

現在,如果您正在編寫財務軟件,其中0.30美元意味着恰好 0.30美元,這是不同的。有針對這種情況設計的十進制算術類。

如何在這種情況下得到正確的結果?

將精度限制爲15位有效數字通常足以隱藏「噪音」數字。除非你真的需要一個確切的答案,這通常是最好的方法。

+0

也許你可以添加到第一段的末尾:「...因爲0.3的二進制表示的無限序列在某個點被切斷,因爲無限值不能存儲在計算機上」。 – josch 2016-08-18 05:46:52