2014-12-25 32 views
1

我的代碼存儲COS和罪成向量和越來越怪異值

double to_radians(double theta) 
{ 
    return (M_PI * theta)/180.0; 
} 

int main() 
{ 
    std::vector<std::pair<double, double>> points; 
    for (double theta = 0.0; theta <= 360.0; theta += 30.0) 
    { 
     points.push_back(std::make_pair(std::cos(to_radians(theta)), std::sin(to_radians(theta)))); 
    } 
    for (auto point : points) 
     std::cout << point.first << " " << point.second << "\n"; 
} 

輸出我希望

1 0 
0.866025 0.5 
0.5 0.866025 
0 1 
-0.5 0.866025 
-0.866025 0.5 
-1 0 
-0.866025 -0.5 
-0.5 -0.866025 
0 -1 
0.5 -0.866025 
0.866025 -0.5 
1 0

輸出我得到:

1 0 
0.866025 0.5 
0.5 0.866025 
6.12303e-17 1 
-0.5 0.866025 
-0.866025 0.5 
-1 1.22461e-16 
-0.866025 -0.5 
-0.5 -0.866025 
-1.83691e-16 -1 
0.5 -0.866025 
0.866025 -0.5 
1 -2.44921e-16

正如你可以看到我得到這些奇怪的值而不是零。有人可以解釋爲什麼會發生這種情況嗎?

+2

我認爲你的數據是正確的,'6.12303e-17'本質上是'0'。 (這是 - 十七次方的6倍,即0.000000000000000006) – BWG

+0

除了提供的答案,[this](http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg。 HTML)是一個有用的閱讀。 – Pradhan

+1

您可能想要檢查您的平臺是否提供(作爲超出當前C++標準的擴展)函數'sinpi()'和'cospi()'。如果是這樣,你應該通過調用'sinpi(theta/180.0)'和'cospi(theta/180.0)'得到更準確的結果。 [CRlibm](http://lipforge.ens-lyon.fr/www/crlibm/)是一個提供這些功能的庫。 – njuffa

回答

10

6.12303e-17舉例來說,代表值6.12303 * 10 -17或0.00000000000000612303。

您獲得此值的原因是您沒有將cos應用於π/ 2,無論如何這不能表示爲double(這是非理性的)。將cos函數應用於接近π/ 2的double,該函數通過將90乘以M_PI併除以180得到。由於參數不是π/ 2,因此結果不一定爲0.實際上,由於浮點數字在零點附近更密集,因此對任何浮點格式應用正確舍入的cos到任何浮點數字都不會產生精確的零結果。

事實上,由於在π/ 2中的cos的導數爲-1,因此表達式cos(M_PI/2.0)獲得的值是M_PI/2與π/ 2之間的差異的近似值。由於雙精度IEEE 754格式只能表示任意數字的前16位左右的第一個十進制數字,因此該差別的確是d * 10 -17的順序。


注意,同樣道理也適用於獲得0.5cos(M_PI/3.0),甚至-1.0cos(M_PI)結果的結果。區別在於有很多浮點數,有些非常小,大約爲0,這些可以非常精確地表示預期的非零結果。相比之下,0.5-1.0只有幾個鄰居,並且對於接近π/ 3和π的輸入,數字0.5-1.0最終作爲最接近的可表示的雙精度值返回到各自的數學結果(其爲isn' t 1/2或-1,因爲輸入不是π/ 3或π)。

對於您的問題最簡單的解決方案是使用假設函數cosdegsindeg,它們將直接計算角度的餘弦和正弦。由於60和90可以完全表示爲雙精度浮點數,所以這些函數不會有任何理由不返回0.5或0.0(也可以精確地表示爲雙精度浮點數)。我早些時候問過a question in relation to these functions,但沒有人指出任何可用的實現。

njuffa指出的函數sinpicospi通常是可用的,它們允許計算正弦和餘弦或π/ 2,π/ 4或甚至7.5 *π,但不是π/ 3, 1/3必須應用於二進制浮點不能完全表示。

0

這是一個浮點舍入錯誤。Trig函數被實現爲數學序列,這些數學序列在導致數字非常接近零的計算水平上近似,例如6.12303e-17而不是預期的0

+2

對於任何非零參數,正確舍入的雙精度「cos」或「sin」不會產生0。實施的細節與此無關。 –

+0

這絕對是真的。你的答案解釋了pi/2是如何接近非理性數字的兩倍,這是一個更好,更簡潔的答案。感謝您的評論。 –