簡體   English   中英

Java浮點澄清

[英]Java floating point clarification

我正在閱讀約書亞布洛赫的Java益智游戲 在謎題28中,我無法理解以下段落 -

這是有效的,因為浮點值越大,值與其后繼值之間的距離越大。 這種浮點值的分布是它們用固定數量的有效位表示的結果。 將1添加到足夠大的浮點值將不會更改該值,因為它不會“縮小”與其后繼的間隙。

  1. 為什么較大的浮點值的值與后繼值之間的距離較大?
  2. Integer情況下,我們添加一個來獲取下一個Integer ,但是如果是float ,我們如何得到下一個float值? 如果我有IEEE-754格式的浮點值,我是否在尾數部分添加1以獲得下一個浮點數?

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

但對於較大的數字,您將開始截斷eg1113500。 下一個可表示的數字是1113600,即100更大。 中間的任何值都不能以此格式表示。 如果您正在讀取此范圍內的值,則必須截斷它 - 找到匹配的最接近的表示,即使它不准確。

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

在另一個極端,對於小值0.0001,下一個可表示的值是0.0002,因此差距僅為0.0001。

浮點值具有相同的原理,但采用二進制編碼(2的冪而不是10的冪)。

您可以將浮點視為基礎2科學記數法。 在浮點數中,您被限制為尾數(也就是有效數字 )和指數的固定位數。 多少取決於您使用的是float (24位)還是double位數(53位)。

考慮基數為10的科學記數法會更為熟悉。 想象一下,尾數限於一個整數,並始終由3位有效數字表示。 現在考慮這個表示中的這兩對連續數字:

  • 100 x 10 0和101 x 10 0 (100和101)
  • 100 x 10 1和101 x 10 1 (1000和1010)

注意,第一對中的數字之間的距離(又稱差異)是1,而第二對中的距離是10.在兩對中,尾數相差1,這是整數之間可以存在的最小差異,但是差異由指數縮放。 這就是為什么大數字在浮點數之間有更大的步數(你的第一個問題)。

關於第二個問題,讓我們看看將1(100 x 10 -2 )加到數字1000(100 x 10 1 ):

  • 100 x 10 1 + 100 x 10 -2 = 1001 x 10 0

但我們僅限於尾數中的三位有效數字,因此最后一個數字被標准化(在舍入后)到:

  • 100 x 10 1

這使我們回到1000.要更改浮點值,您需要添加該數字與下一個數字之間差異的至少一半; 這個最小差異隨着數字的大小而變化。

二進制浮點正在發生同樣的事情。 有更多細節(例如,歸一化,保護數字,隱含小數點,隱含位),您可以在優秀的文章中了解每個計算機科學家應該知道的關於浮點運算的內容

  1. 浮點數表示為尾數和指數的組合,其中數字的值是mantissa * 2^(exponent)所以如果我們假設尾數限制為2位數(為了使事情更簡單)並且你有數字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,並且可能需要處理溢出以獲取next / prev值。

雖然它沒有解釋原因,但是此示例代碼顯示了如何計算浮點數與下一個可用浮點數之間的距離,並給出了一個大數字的示例。 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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM