這個文檔沒有特別好的解釋,但是Double.toString(double)
本質上是對它產生的輸出進行一些四捨五入。在整個Java SE中都使用了Double.toString
算法,包括例如PrintStream.println(double)
的System.out
。文檔說這個:
多少位必須打印爲米或一個小數部分?必須至少有一位數字來表示小數部分,並且除此之外還必須包含儘可能多的數字,但數量必須與唯一地區分參數值與類型爲double
的相鄰值所需的位數相同。也就是說,假設x是由該方法對有限非零參數產生的十進制表示法所表示的確切數學值d。然後d必須是最接近x的double
值;或者如果兩個double
值同樣接近X,然後d必須是其中之一,並d的有效數必須0
的至少顯著位。
換句話說,它表示toString
的返回值不一定是參數的精確十進制表示形式。唯一的保證是(粗略地說)參數比任何其他double
值更接近返回值。
因此,當您執行類似System.out.println(1.10)
和1.10
的打印時,這並不意味着傳入的值實際上等於基本10值1.10
。相反,本質上會發生以下情況:
- 首先,在編譯過程中,字面
1.10
檢查並四捨五入產生最接近double
值。 (它說在JLS here此規則是在Double.valueOf(String)
例如詳細爲double
。)
- 第二,當程序運行時,
Double.toString
產生一些十進制值,其在先前的步驟中產生的double
值接近的String
表示比任何其他double
值。
恰巧在第二步轉換爲String
經常產生一個String
,它與第一步中的文字相同。我會假設這是設計。無論如何,文字例如1.10
不會產生一個double
的值,它正好等於1.10
。
您可以使用BigDecimal(double)
構造發現一個double
的實際值(或float
,因爲他們總能適合在double
):
當double
必須用作源的BigDecimal
,請注意,此構造函數提供了精確的轉換;它不會給出與使用Double.toString(double)
方法將double
轉換爲String
然後使用BigDecimal(String)
構造函數相同的結果。要獲得該結果,請使用static
valueOf(double)
方法。
// 0.899999999999999911182158029987476766109466552734375
System.out.println(new BigDecimal((double) (2.00 - 1.10)));
// 0.89999997615814208984375
System.out.println(new BigDecimal((float) (2.00 - 1.10)));
你可以看到,無論結果實際上是0.9
。在這種情況下,Float.toString
碰巧產生0.9
,Double.toString
不會產生或多或少的巧合。
作爲一個附註,(double) (2.00 - 1.10)
是一個冗餘的演員。 2.00
和1.10
已經是double
文字,所以評估表達式的結果已經是double
。此外,要減去float
,則需要投射兩個操作數,如(float) 2.00 - (float) 1.10
或使用float
文字,如2.00f - 1.10f
。 (float) (2.00 - 1.10)
僅將結果轉換爲float
。
閱讀[this](https://stackoverflow.com/questions/588004/is-floating-point-math-broken) –
「也許默認情況下Java執行雙倍計算」,因爲'2.00'和'默認情況下,1.10'被認爲是雙打(除非你明確聲明它們應該是浮動的,就像加上'f'後綴),所以'double + double = double'的結果解釋了爲什麼要投射'(double)(2.00-1.10)不會改變任何東西。 – Pshemo
@biziclop,雖然涉嫌重複與此問題有關;這個版本的問題有所不同。所謂的重複不會解釋這個問題的最基本的方面:爲什麼向下轉換解決了這個問題? –