簡體   English   中英

Java(IEEE 754)中浮點數(float,double)的計算精度

[英]The calculation accuracy of floating-point numbers (float, double) in Java (IEEE 754)

我在 JDK 11 的jshell中嘗試了以下計算:

jshell> 0.1 + 0.2 == 0.3
$1 ==> false

我可以理解這種回報。 畢竟,0.1、0.2 或 0.3 都不能准確地用二進制表示。

但是當我切換到float而不是double時,我驚訝地發現jshell的返回是true

jshell> 0.1f + 0.2f == 0.3f
$2 ==> true

這與我一直以來的理解背道而馳。 所以我嘗試讓jshell直接計算:

jshell> 0.1 + 0.2
$3 ==> 0.30000000000000004

jshell> 0.1f + 0.2f
$4 ==> 0.3

確實,如果我使用float數據類型,它似乎能夠准確地計算出結果為0.3

但為什么? 如果double不能准確表示和計算0.1 + 0.2 ,那為什么float可以呢?

如果我的測試有任何錯誤,請指出。 先謝謝了!

即使作為浮點數,這個數字實際上也不是 0.3。

    public static void main (String[] args) throws java.lang.Exception
    {
        float a = 0.1f;
        float b = 0.2f;
        float c = 0.3f;
        float d = a + b;
 
        System.out.println( new BigDecimal(c) + ", " + new BigDecimal(d));
    }

這樣就出來了。

0.300000011920928955078125, 0.300000011920928955078125

您發現了錯誤正在抵消的情況。

這類似於使用十進制系統,並添加 1/3 + 2/3。 1/3 約為 0.333,2/3 約為 0.667,因此當您將兩者相加時,即使它們都是近似值,您也會得到 1.0。

每次執行浮點運算時,理想的實數算術結果都會被舍入到浮點格式中可表示的最接近的值,使用適用於運算的任何舍入方法(最常見的是舍入到最近的關系-甚至)。

有時四舍五入的方向會取消先前的四舍五入。 有時四舍五入的方向會加劇先前的四舍五入。

將源文本0.1轉換為double是浮點運算。 它產生 0.1000000000000000055511151231257827021181583404541015625,因此四舍五入使結果更大。

0.2轉換為double會產生0.200000000000000011102230246251565404236316680908203125 ,再次更大。

0.3轉換為 double` 會產生 0.299999999999999988897769753748434595763683319091796875,因此四舍五入使結果更小。

添加前兩個,0.1000000000000555515123125782782118158340454541015625和0.2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002330251515151515425423636823166824125125125125125,00125,00125,00125,0025,0025,0025,0025,0025,0025,0025,0025,0025,0025,0025,0025,0025,0025,0025,0025,0025,0025,0025,.x 在這里四舍五入再次增加了結果。

0.1f轉換為float會產生 0.100000001490116119384765625。

0.2f轉換為float會產生 0.20000000298023223876953125。

0.3f轉換為float會產生 0.300000011920928955078125。 在這種情況下,由於float中可表示的數字少於double中可表示的數字,因此下一個低於 0.3 的float值距離 0.3 比 0.300000011920928955078125 更遠。 因此,即使將0.3轉換為double舍入,也將0.3f轉換為float

添加這些float值的前兩個,0.100000001490116119384765625 和 0.20000000298023223876953125,產生 0.300000011920928955078125。 由於這與轉換0.3f的結果相同,因此0.1f + 0.2f == 0.3f評估為真。

需要注意的另一件事是,Java 對浮點數的默認顯示只產生足夠的有效數字來唯一區分其浮點格式中的值。 這意味着,當 Java 顯示數字“0.3”時,並不表示浮點值為 0.3。 這意味着浮點值比該格式中的任何其他值更接近 0.3,因此打印“0.3”足以識別它。

這意味着當為double打印“0.3”時,實際的double值為 0.299999999999999988897769753748434595763683319091796875,但是,當為float打印“0.3”時,實際的float值為 0.300000011920928955078125。 Java 並非旨在向您顯示浮點數的真實值。

暫無
暫無

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

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