2013-03-21 197 views
3

我有問題關於雙精度。當float值傳入double時,我得到一些不同的結果。對於例如雙精度浮點值傳遞雙精度時

float f= 54.23f; 
double d1 = f; 
System.out.println(d1); 

輸出是54.22999954223633。有人能解釋這種行爲背後的原因嗎?它是否像雙精度值到十進制精度的十四個位置?

回答

-1

doublefloat代表不同格式的數字。

正因爲如此,你一定會發現某些數字完全以一種格式存儲,而不是另一種格式。你碰巧找到了一個正確匹配float,但不適合exactly的「double」。

當兩個不同的格式化程序被使用時,這個問題也會出現。

+4

'double'使用與'float'相同的基本格式,它只是使用更多的位。每個「float」值都應該可以用「double」來表示。 – 2013-03-21 13:53:58

+0

@JoachimSauer:對於每個'float',都有一個具有相同標稱值的'double',但浮點數的含義超出了標稱值。考慮下面的問題:「將一個3.0cm的釘子固定在一個3.002cm的洞裏?」和「3.000釐米的釘子會套在3.002釐米的洞裏嗎?」兩個釘子的標稱尺寸完全相同,但是後者釘子被指定爲合適的,而前者不是(即使它是3.004釐米,仍然可以被描述爲3.0釐米釘子)。沒有與任何「浮動」值相同的「含義」的「雙」值;對於兩個值來說,沒有'double'更接近。 – supercat 2013-07-25 23:38:45

0

這是因爲float隱藏了額外的小數,double顯示它們。雙數將精確地表示實際數字並顯示更多數字。

嘗試這種情況:

的System.out.println(f.doubleValue()); (需要使它成爲Float第一個課程)

所以,你可以看到,信息在那裏,它只是圓形。 希望這有助於

+0

很可能'f.doubleValue()'被實現爲'new Double(f)'。 – OldCurmudgeon 2013-03-21 13:49:30

+0

@OldCurmudgeon,它是演員。 'return(double)value;' – jn1kk 2013-03-21 13:51:01

+1

這很接近,但並不完整。打印「雙」並不總是顯示更精確;有時它會顯示與在「float」中打印相同值相同的結果。實際的規則是打印的數字必須是打印傳遞的值是最接近數字值的類型的值(帶有關於關係的一些附加規則)。這通常會導致'double'顯示的數字比'float'更多,但並非總是如此。 – 2013-03-21 15:05:26

0

這是由於Internal Representation
浮點數通常從左到右依次包含在計算機數據中,作爲符號位,指數字段和有效位數(尾數)。

這被稱爲Accuracy Problems
浮點數不能精確表示所有實數並且浮點運算不能精確表示真正的算術運算的事實會導致很多令人驚訝的情況。這與計算機通常表示數字的有限精度有關。

這不是問題。這是雙重作品。你不必處理它並關心它。雙精度就足夠了。想想,你的數字和預期結果之間的差異是在小數點後的14位。

如果您需要任意高精度,請使用java.math.BigDecimal類。

或者如果你還想使用雙。這樣做:

double d = 5.5451521841; 
NumberFormat nf = new DecimalFormat("##.###"); 
System.out.println(nf.format(d)); 

如果有任何疑問,請讓我知道。

+0

我不相信這個問題是關於爲什麼'54.23f'沒有54.23的值,但是爲什麼將它打印爲'double'顯示的數字比打印爲'float'的數字要多,即使打印的是相同的值。 – 2013-03-21 15:06:09

0

其實這只是關於不同的視覺表示或將float/double轉換爲String。讓我們來看看內部二進制表示

float f = 0.23f; 
    double d = f; 
    System.out.println(Integer.toBinaryString(Float.floatToIntBits(f))); 
    System.out.println(Long.toBinaryString(Double.doubleToLongBits(d))); 

輸出

111110011010111000010100011111 
11111111001101011100001010001111100000000000000000000000000000 

這意味着f轉化爲d1沒有任何失真,顯著數字是相同的

+0

這是如何回答這個問題的? – 2013-03-21 15:06:37

+0

Double.toString以不同的方式轉換0.23f,而實際值相同 – 2013-03-21 15:10:29

+0

這並不能解釋原因。 **相同值**的打印方式有何不同? – 2013-03-21 15:11:07

6

相同的值被打印不同對於floatdouble,因爲Java規範要求根據需要打印儘可能多的數字以區分相同值中的值和相鄰的可表示值鍵入(根據我的回答here,並在定義中查看linked documentation以獲得更高精度)。

由於float只有較少的位來表示值,因此值越小,它們的間隔就越大,並且不需要很多數字來區分它們。將值放入double並打印出來時,Java規則要求打印更多數字,以便將值與附近的double值區分開來。函數println不知道該值最初來自float,並且沒有包含儘可能多的信息以適應double

54.23f正好是54.229999542236328125(十六進制,0x1.b1d70ap + 5)。剛剛低於此值的float值爲54.2299957275390625(0x1.b1d708p + 5)和54.23000335693359375(0x1.b1d70cp + 5)。正如你所看到的,打印「54.229999」將區分54.229995 ...和54.23 ...的值。然而,正好低於54.23fdouble值是54.1957264239899814128875732421875和54.22999954223633523042735760100185871124267578125。要區分這個值,你需要「54.22999954223633」。

+0

我真的不喜歡將隱式'float'轉換爲'double'轉換的一個原因是,即使從位級的角度來看,像0x1一樣。B1D708A + 5是二次冪分數的完美表示,浮點變量更典型地用作不是二次冪次冪數的不完美表示。如果我知道最接近某個數字的'float'是0x1.B1D708A + 5,這意味着該數字在一定的範圍內,但應該被認爲與該範圍內的其他值無法區分。將其轉換爲「double」... – supercat 2013-09-04 07:23:12

+0

...將虛假地假設並暗示該變量旨在表示的數字非常接近「float」可以表示的數字範圍的中心,儘管在實踐中存在這個假設可能沒有可信的基礎。關於16777217f和16777216.0001作爲等級排列,恕我直言不如將前一個值排在較低位置(如果比較運算符將兩個操作數隱式轉換爲「double」,會發生什麼情況)。 – supercat 2013-09-04 07:28:34

+0

這是一種不正當的用法。 'float'和'double'都不能攜帶關於它周圍區間的任何信息。它代表一個單一的數字。有些人認爲它代表了一個間隔,比如說相鄰值的中點。但是,只有執行了單個操作(例如從十進制到二進制浮點的轉換),情況纔會成立。經過一次以上的操作後,錯誤可能會更大,並且它不會如何增長。因此,如果要表示區間信息,則它必須在單獨的數據中進行...... – 2013-09-05 15:04:47