2016-11-24 49 views
-1

我:Math.sin給人怪異的答案

double num1 = sc.nextInt(); 

我用:

double sin = Math.sin(Math.toRadians(num1)); 

並取得輸出:

if(calc.contains("sin")) { 
    System.out.println (sin); 
} 

如果我輸入了NUM1:

30它計算罪惡。它給我0.49999999999999994

+1

請閱讀[每個計算機科學家應該瞭解的浮點算術知識](https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html) –

+1

對不起,我沒有認爲這是這個問題的重複。通常的「浮點算術被打破」解釋了爲什麼像'0.1'這樣的特定數字不能完全表示。但0.5 **可以完全代表**,所以這個問題的答案肯定是不同的。 – ajb

+0

@ajb是的,0.5可以精確表示,但pi/6不能。所以我們把一個精確的30轉換成一個不精確的pi/6,然後找到一個不完全是0.5的正弦。 –

回答

0

sin(30°)肯定是0.5,但是沒有一個字典包含一個密鑰30°,其值爲0.5,所以計算機需要計算它。

enter image description here

的公式表示以上。

讓我們計算sin(30°),30°=π/ 6,所以F(X)=π/ 6 - π^1296分之3 - π^九十三萬三千一百二十○分之五 - ....

而那麼在這個過程中,準確性錯誤會導致「不可預測的」(實際上可預測的)問題。

+0

我認爲這個答案忽略了一點。 「罪」的合約說結果必須在1 ULP「正確」之內。但問題在於對「罪」的爭論 - 這就是不精確的「π/ 6」。 –

+0

@DavidWallace你是對的,π/ 6的不精確性是這種情況下的實際精度誤差。 – Sraw

2

π/ 6不能完全在計算機中表示(它不能完全表示在紙上)。這會導致結果稍微偏離。使用Unix高精度計算器「bc」(注意:我不知道正弦和餘弦的準確程度),我發現程序中的實際值是π/ 6 +ε,其中ε是大約5.3604×10 -17。使用sin公式(x + y),預期的結果應該是sinπ/6cosε+sinεcosπ/ 6。 cosε約爲1 - 10 -33,所以這種差異不足以影響結果。然而,sinεcosπ/ 6大約爲4.64x1-17。所以實際結果應該是0.4999999999999999535774978而不是0.5。

這個結果也不會完全代表double。由於double具有52位的尾數,因此其值大於等於0.25且等於或大於0的數字可以由多達2 -54的數字表示。用於表示此結果的double將是0.499999999999999944488848768742172978818416595458984375。如果打印出的文字是System.out.println,打印後會在一定數量的小數位後停止,所以這會被截斷爲0.49999999999999994,這是您看到的結果。 (顯示的位數在[http://docs.oracle.com/javase/8/docs/api/java/lang/Double.html#toString-double-](this javadoc中討論]。

+0

對不起,以前我沒有看到。 – ajb