2015-07-20 374 views
1

這是我沒有想到的。我知道這些數字是不準確100%,但我沒想到餘角給人sin不同的結果和cos爲什麼sin(45)和cos(45)給出不同的結果?

這下面的函數返回0.70710678118654746000000...

sin(45 * PI/180.0); 

而這follwing函數返回0.70710678118654757000000...

cos(45 * PI/180.0); 

所以,它的:

0.707106781186547**46**000000... vs 
0.707106781186547**57**000000... 

而不僅僅是... sin(1 * PI/180.0)也返回比cos(89 * PI/180.0)略有不同數量雖然他們應該是相同的。

而且這不僅是一個sin VS cos問題,它也是一個sin VS sin問題:sin(1 * PI/180.0)sin(179 * PI/180.0)返回不同的值,他們又應該是相同的。

我試圖用弧度,而不是學位,並有完全一樣的區別,我試圖用一個小的PI值,一個巨大的PI值(約100個小數和更多),他們還在不同的,我試過使用cmath而不是math.h,我試圖使用M_PI而不是我自己定義的PI

其差值總是相同的,大約在小數點後16位。不要誤解我的意思,我知道我永遠不會得到這些數字的100%精確值,但至少我期望得到相互補充角度的sincos相同的「不精確」值。這一切到底是什麼錯誤?


我需要他們一樣,因爲我的工作(重力模擬器我被要求做)的程序使用具有double(我也試過float)對象它們基本上角度變量(度或弧度,我都試過)。這些是物體移動的方向,也需要角度來計算物體之間的相互作用。

在程序的每一次迭代中角度都會改變,並且在每次迭代中,角度都會根據前一次迭代角度的計算而改變,所以如果在任何一點上有任何最小錯誤的角度值,該誤差會被放大得更多並在每一次迭代中更多。

該程序運行數千甚至數百萬次的迭代,所以該值的錯誤變得荒謬可笑!說得清楚,行星最終得到了他們的平衡,一切都變得一場災難,我真的瘋了:(

附言:我在Windows 7中,32位。

+2

這裏只有約16的精度十進制數字在編譯雙倍。 – ooga

+0

嗯,我知道我永遠不會爲罪(45)獲得完美的價值,這樣的價值不存在,完美的圓形PI值也不存在,但我至少期待互補的角度出錯以相同的方式:/ – Dimakhaerus

+1

您可能想要查找(或實現)符號計算庫。當然,你會爲了精確而犧牲性能。 –

回答

3

我知道我會從來沒有得到這些數字的100%的精確值,但 至少我是期望得到互補角度的正弦和餘弦 的相同的「unprecise」值。

爲什麼?計算方式不同,因此會發生不同的浮點錯誤(並累計)。你看到的不是一個錯誤;數學規律並不能預測FP算術。

順便說一句,提供例如。如果您的類型不能保持30位數字,則30或100位數字的PI不會有任何不同

+0

我知道關於PI的事情,這是一個絕望的嘗試,使其正常工作。 那麼,這顯然是一個巨大的錯誤,無論他們如何計算,他們應該返回相同的值:/ 感謝您的回答! – Dimakhaerus

+0

@Dimakhaerus如果你認爲它是一個錯誤,那麼提出解決方案怎麼樣?對,不可能達到這樣的期望,因爲有這樣的無限特殊情況。例如'sin(60)== sqrt(3)/ 2'是另一個。 ......如果沒有足夠的內存,就會出現錯誤,而且沒有任何東西可以阻止這種情況發生。 – deviantfan

+0

即使提供30位數字對於大多數用途來說都是過度殺傷,從內存來看,「355/113」足以在地球表面定位汽車。 '3.141592653589'(我可以記住我的頭頂)可能(但我沒有檢查)在太陽系中找到豌豆:-) – paxdiablo

2

不管它們是如何計算出來的,他們應該返回相同的值

您的期望是不正確的。在IEEE-754中,只有基本操作員(+-*/)和sqrt需要正確舍入。 Trancendental功能,如sincosexp ...不是必需的,因爲它是非常複雜的

沒有標準,需要超越函數忠實四捨五入。 IEEE-754(2008)建議,但不要求,這些函數被正確舍入。


現在,如果你看一下你的價值觀

         ↓ 
0.70710678118654746 = 0x1.6a09e667f3bccp-1 
0.70710678118654757 = 0x1.6a09e667f3bcdp-1 
             ↑ 

因此,他們是彼此的1ulp內,並且足夠精確的雙精度爲

不要誤會我的意思,我知道我將永遠不會得到這些數字的100%的精確值,但至少我期待得到同樣的「unprecise」罪的餘角

的價值和cos

不僅有一個算法來計算sincos。對於某些輸入集合,每個輸入都是正確的,但對其他輸入不正確。他們也有不同的內存和時間要求,所以有些人可能會有更快的錯誤,有些需要更多的時間和內存,但他們可以達到更高的準確度。

編譯器實現可能對這些函數使用不同的算法,所以如果您需要一致的結果,請使用跨平臺的精心設計的單個庫。例如,GCC使用MPFR來實現正確舍入的結果,而不管平臺如何。

GCC中端已經與MPFR庫集成。這使得GCC可以在編譯時調用內置的數學函數來評估和替換具有恆定參數的內置數學函數以及它們的數學等價結果。在使用MPFR時,無論數學庫實現或主機平臺的浮點精度如何,GCC都可以生成正確的結果。這也允許GCC以產生相同的結果而不管中的一個是否在天然或交叉編譯配置到特定目標

https://gcc.gnu.org/gcc-4.3/changes.html#mpfropts

How does C compute sin() and other math functions?

+0

謝謝!它給了我一個更好的想法,說明爲什麼我的程序失敗了,當我的cos和sin值應該是相同的時候,我會試着強迫他們實際上是相同的,如果這不起作用,我會嘗試像你說的一個不同的圖書館! :) – Dimakhaerus

+1

只是一個小小的附錄:即使你對'sin'和'cos'有一個'確切'的實現(即一個從不錯過0的錯誤)。5ulp),因爲輸入參數不完全是PI/4(取決於這個輸入值如何舍入,正弦或餘弦將變大),所以在這裏你不會得到相同的正弦和餘弦值。在計算'sin(M_PI)'時(這不是0.0),你實際上可以觀察到類似的問題。 – chtz

相關問題