2017-07-14 91 views
0

如果你問我,下面的例子給出的結果是超級怪異的。這怎麼可能?有沒有辦法將這兩個值恰當地相加? Float.sum(float a,float b)也給了我相同的結果。爲什麼總是不能正確求和兩個浮點值?

import java.text.DecimalFormat; 

public class HelloWorld { 
    public static void main(String[] args) { 
    System.out.println("Sum: " + new DecimalFormat("#").format((1500036225984102400.f + 2000000000.f))); 
    } 
} 

輸出是:

總:1500036225984102400

我當然會期待這兩個值得到總結,但它似乎是第二個值纔剛剛被忽略?

回答

1

如果你看看如何設置float(IEEE-754),你很快就會發現尾數只有23位(實際上是24位,其中一個對於非非規範化數是隱含的)。

1500036225984102400是十六進制的

14 d1 3300 00 00 00 00
所以你看,數字的非零部分適合這24位。這就是爲什麼你打印的數字完全按照你的要求打印的原因。任何進一步的比特將被簡單地切斷(類似於整數除法,儘管不完全相同)。其實,這在數學上是四捨五入的。

所以,如果你現在比較你的兩個數字:

 
14 d1 3300 00 00 00 00 
      77 35 9400
你很快就會看到添加的結果不適合可用的24位,什麼不適合,只是簡單地舍掉了–正是你試圖添加的數字...

這通常是一個浮點數的問題,但得到更少的可見與雙倍尾數和指數都只是更大的那裏...

4

浮點數的精度有限。您可以使用Math.nextUp方法找到可表示的下一個最大號碼。例如,你可以使用找到一個比你的第一個操作數的下一個最大數:

float next = Math.nextUp(1500036225984102400.f); 

可以使用Math.ulp得到一個編號,它的下一個最大的數或者通過減之間,或跳轉的大小,它告訴你一個「單位在最後的地方」的大小,如果你調整最低顯著位數量的增加量:

float ulp = Math.ulp(1500036225984102400.f); 

你會發現,這個數字大於2000000000.f

Math.ulp(1500036225984102400.f) = 137438953472.0 
            2000000000.0 

因此,您的兩個數字的總和不能用float1500036225984102400.f更精確地表示。

相關問題