2012-07-12 38 views
4

代碼 [GCC,以-02標誌編譯]正確性CMATH的戰俘()在GCC

int main() 
{ 
    vector< vector<int> > matrixa(8); 
    int ff = 5; 
    int s = pow(ff, matrixa.size()); 
    int ss = pow(double(ff), int(matrixa.size())); 
    vector< vector<int> > comb(s); 
    cout << ff << "^" << matrixa.size() << " = " << s << endl; 
    cout << ss << endl; 
    return 0; 
} 

輸出

5^8 = 390624 
390625 

我不知道爲什麼s = 390624時,它應該是390625。如果我編譯沒有-O2標誌的代碼,那麼s = 390625。此外,ss的鑄件似乎可以糾正該問題。

這是怎麼回事?

我的操作系統是Windows 7旗艦版64位。不知道GCC版本,它帶有Code :: Blocks 10.05。

+0

我認爲,來了一個4.4.1 IIRC。 – chris 2012-07-12 16:14:45

+0

'雙POW(雙,INT)'除去在C++ 11順便說一句 – 2012-07-12 16:16:31

+0

正確地工作這裏(GCC-4.5.1和Linux)。 – 2012-07-12 16:16:33

回答

6

因爲浮點運算是不完美的,當你做

int s = pow(ff, matrixa.size()); 

pow的結果實際上是更多的東西一樣390624.99999當你把它截斷爲int它有效地被夷爲平地下降到390624.如果您期望在那裏有一個整數值(一個帶有.0小數部分的浮點數),你應該圍繞pow的結果。

+3

此錯誤不是由浮點運算引起的。 POW(5,8)是一個雙精確表示的,所以一個好的數學庫應該恰好返回390625.即使是隻保證忠實舍(小於1 ULP),而不是正確的舍入(不超過1/2 ULP帶圖書館領帶四捨五入甚至)將在這裏得到正確的答案。所以,如果pow沒有返回正確的答案,問題是庫的質量,而不是浮點運算。 – 2012-07-12 18:02:25

+1

@EricPostpischil是的,但是如果浮點算法是絕對理想的(這不是,也不是我的答案的重點),即使(pow)實現背後的(窮)算法也不會產生任何偏差。所以實際上可以說它是由IEEE浮點運算引起的。但我完全同意你的觀點,這是在這種特殊情況下'pow'的實現。 – 2012-07-12 18:27:29

+1

理想的算術,就每個操作產生精確的數學結果而言,不會導致pow產生正確的結果。這是因爲浮點運算僅提供加法,減法,乘法,除法,平方根和一些實用操作。這些不足以計算pow(對於一般參數;顯然可以計算pow(5,8)等特定情況),因爲算術運算只能計算以平方根擴展的有理函數。因此,pow和其他數學函數庫函數必須近似,即使算法完美。 – 2012-07-12 18:36:30

5

嘗試結果賦給一個double和輸出它(具有可能的更大std::setprecision)設置。你會看到由於舍入誤差,該值將是類似390624.99999999999(或類似)。

鑄造爲int截斷小數部分,從而讓你有390624。使用std::round可以獲得所需的結果。