2013-08-07 81 views
2

我在閱讀Joshua Bloch的Java puzzlers。在拼圖28,我無法理解以下中─Java浮點數說明

這樣做是因爲價值和它的後繼者之間的一個浮點值越大, 距離越大。浮點值的這種分佈是由於它們用 固定數量的有效位表示的結果。將1加到足夠大的浮點值 將不會更改該值,因爲它不會將「間隙」與其後繼者「聯繫起來」。

  1. 爲什麼較大的浮點值的值與後繼之間的距離較大?
  2. Integer的情況下,我們添加一個獲得下一個Integer,但在float的情況下,我們如何獲得下一個float值?如果我擁有IEEE-754格式的浮點數值,我是否將尾數部分加1以獲得下一個浮點數?因此,如果我們假設尾數限制爲2個位數

回答

4

你可以認爲浮點爲基礎-2科學計數法。在浮點上,尾數限制爲固定位數(又名有效數字)和指數。有多少取決於您使用的是float(24位)還是double(53位)。

想想基地10科學記數法,這有點更熟悉。想象一下,尾數限制爲一個整數,並且總是由3位有效數字表示。現在考慮這兩對連續數字的在此表示:

  • 100×10 和101×10 (100和101)
  • 100×10 和101×10 (1000和1010)

注意的是,在第一對數之間的距離(也稱爲差)爲1,而與第二對是10.在這兩個對,尾數相差1, whic h是整數之間的最小差值,但差值由指數縮放。這就是爲什麼更大的數字在浮點之間有更大的步距(你的第一個問題)。

關於第二個問題,讓我們來看看添加1(100×10 -2)與數1000(100×10 ):

  • 100×10 + 100 ×10 -2 = 1001×10

但我們被限制爲只有三個顯著位數的尾數,那麼最後一個號碼GE TS標準化(四捨五入後)到:

  • 100×10

這讓我們回到1000要改變一個浮點值,則需要添加至少一半的區別該號碼和下一個號碼;這個最小差異隨數字的大小而變化。

完全相同的事情正在進行與二進制浮點。有更多的細節(例如,規範化,守衛數字,隱含小數點,隱含位),你可以在優秀的文章What Every Computer Scientist Should Know About Floating-Point Arithmetic

+0

中閱讀有關很好的答案,很好的鏈接。謝謝! –

3
  1. 浮點數表示爲尾數 和指數,其中數字的值是mantissa * 2^(exponent)的組合(使事情變得更簡單),你具有號碼1.1 * 2^100, ,這是非常大的,「下一個」值將是1.2 * 2^100。所以如果 你做混合尺度計算,1.1*2^100 + 1將 四捨五入回1.1*2^100因爲尾數沒有足夠的空間保留準確的結果。
  2. 以java開頭6您有一個實用方法Math.nextUp()Math.nextAfter(),它將允許您「遍歷」所有可能的double/float值。在此之前,您需要將+1加到尾數,並且可能需要注意溢出以獲取下一個/ prev值。
5

想象一下你只能設置前5個值(即你的尾數是5的長度)的基於十進制的格式。對於小的數字,你會被罰款: 1.0000, 12.000, 125.00

但對於更大的數字,你會開始有截斷e.g.1113500。下一個可表示的數字將是1113600,大於100。兩者之間的任何值都不能用這種格式表示。如果你正在閱讀這個範圍內的值,你將不得不截斷它 - 找到匹配的最接近的表示,即使它不是確切的。

數字越大,問題越嚴重。如果我達到34567800000,那麼下一個可表示的數字將是34567900000,這是1000000或100萬的差距。通過這種方式,您可以看到表示之間的差異取決於大小。

在另一個極端,對於小的值0.0001,下一個可表示的值是0.0002,因此間隙僅爲0.0001。

浮點值具有相同的原理,但具有二進制編碼(兩個冪而非十的冪)。

2

雖然它沒有解釋爲什麼,但此示例代碼顯示瞭如何計算浮動點和下一個可用浮動點之間的距離,並給出了大量示例。 fg應該是Integer.MAX_VALUE,但它們是相同的。而下一個值是h,這是1099511627776較大。

float f = Long.MAX_VALUE; 
System.out.println("f = " + new BigDecimal(f)); 
System.out.println("f bits = " + Float.floatToIntBits(f)); 
float g = f - Integer.MAX_VALUE; 
System.out.println("g = f - Integer.MAX_VALUE = " + new BigDecimal(g)); 
System.out.println("g bits = " + Float.floatToIntBits(g)); 
System.out.println("f == g? " + (f == g)); 
float h = Float.intBitsToFloat(Float.floatToIntBits(f) + 1); 
System.out.println("h = " + new BigDecimal(h)); 
System.out.println("h bits = " + Float.floatToIntBits(h)); 
System.out.println("h - f = " + new BigDecimal(h).subtract(new BigDecimal(f))); 

輸出:

f = 9223372036854775808 
f bits = 1593835520 
g = f - Integer.MAX_VALUE = 9223372036854775808 
g bits = 1593835520 
f == g? true 
h = 9223373136366403584 
h bits = 1593835521 
h - f = 1099511627776