Java中的浮点精度和相等性 [英] Floating point precision and equality in Java

查看:191
本文介绍了Java中的浮点精度和相等性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

知道浮点数,即使是十进制格式的小数点后的固定数字的浮点数,也不能完全表示。所以我有以下的程序来测试:

pre $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $公共类主要$ b $公共静态无效main(String [] args ){
System.out.printf(0.1单精度为%.50f \ n,0.1f);
System.out.printf(0.2单精度为%.50f \ n,0.2f);
System.out.printf(0.3单精度为%.50f \ n,0.3f);
System.out.printf(0.1 + 0.2单精度为%.50f \ n,0.1f + 0.2f);
System.out.printf(0.1 + 0.2 == 0.3 is%b in single precision \\\
,0.1123f * 0.4f + 0.2f * 0.5f == 0.2f * 0.7f + 0.0123f * 0.4F);

System.out.println();

System.out.printf(0.1,双精度为%.50f \ n,0.1);
System.out.printf(0.2中的双精度为%.50f \ n,0.2);
System.out.printf(0.3中的双精度为%.50f \\\
,0.3);
System.out.printf(0.1 + 0.2,双精度为%.50f \ n,0.1 + 0.2);
System.out.printf(0.1 + 0.2 == 0.3 is%b in double precision\\\
,0.1 + 0.2 == 0.3);


code
$ b $ p $输出如下:

  0.1单精度为0.10000000149011612000000000000000000000000000000000 
单精度0.2为0.20000000298023224000000000000000000000000000000
0.3单精度为0.3000000119209289600000000000000000000000000000000
0.1 + 0.2单精度为0.30000001192092896000000000000000000000000000000000
0.1 + 0.2 == 0.3单精度为真

0.1双精度为0.10000000000000000000000000000000000000000000000000
0.2双精度为0.20000000000000000000000000000000000000000000000000
0.3的双精度是0.30000000000000000000000000000000000000000000000000
0.1 + 0.2的双精度是0.30000000000000004000000000000000000000000000000000
0.1 + 0.2 == 0.3是双精度的错误

从上面的结果我不能回答两个问题,我正在寻求帮助:


  1. 为什么 0.1 0.2 0.3 看起来确切,但是 0.1 + 0.2 不。为什么 0.1f + 0.2f == 0.3f 返回true?


  2. 解决方案


    1. 我怀疑 System.out.printf 在这里正常工作。一个可靠的方法来获得当你写0.1时得到的确切的 double 值是写新的BigDecimal(0.1).toString()

    2. 为什么0.1f + 0.2f == 0.3f返回true?非常幸运的是:你可以将0.1加到最接近的浮点数表示上,将0.2加到最接近的浮点数上,然后加上它们就可以得到0.3的最接近的浮点数。这通常不是真的,这些价值恰好是工作。


    It's know that floating point number, even those with fixed digits after decimal point in decimal format, can't be represented exactly. So I have the following program to test:

    public class Main {
      public static void main(String[] args) {
        System.out.printf("0.1 in single precision is %.50f\n", 0.1f);
        System.out.printf("0.2 in single precision is %.50f\n", 0.2f);
        System.out.printf("0.3 in single precision is %.50f\n", 0.3f);
        System.out.printf("0.1 + 0.2 in single precision is %.50f\n", 0.1f + 0.2f);
        System.out.printf("0.1 + 0.2 == 0.3 is %b in single precision\n", 0.1123f * 0.4f + 0.2f * 0.5f == 0.2f * 0.7f + 0.0123f * 0.4f);
    
        System.out.println();
    
        System.out.printf("0.1 in double precision is %.50f\n", 0.1);
        System.out.printf("0.2 in double precision is %.50f\n", 0.2);
        System.out.printf("0.3 in double precision is %.50f\n", 0.3);
        System.out.printf("0.1 + 0.2 in double precision is %.50f\n", 0.1 + 0.2);
        System.out.printf("0.1 + 0.2 == 0.3 is %b in double precision\n", 0.1 + 0.2 == 0.3);
      }
    }
    

    The output is the following:

    0.1 in single precision is 0.10000000149011612000000000000000000000000000000000
    0.2 in single precision is 0.20000000298023224000000000000000000000000000000000
    0.3 in single precision is 0.30000001192092896000000000000000000000000000000000
    0.1 + 0.2 in single precision is 0.30000001192092896000000000000000000000000000000000
    0.1 + 0.2 == 0.3 is true in single precision
    
    0.1 in double precision is 0.10000000000000000000000000000000000000000000000000
    0.2 in double precision is 0.20000000000000000000000000000000000000000000000000
    0.3 in double precision is 0.30000000000000000000000000000000000000000000000000
    0.1 + 0.2 in double precision is 0.30000000000000004000000000000000000000000000000000
    0.1 + 0.2 == 0.3 is false in double precision
    

    Two questions I can't answer from the above result and I am seeking help for:

    1. Why does the double representation of 0.1, 0.2 and 0.3 looks exact, whereas 0.1 + 0.2 doesn't.
    2. Why does 0.1f + 0.2f == 0.3f return true?

    解决方案

    1. I am suspicious of System.out.printf working correctly here. A reliable way to get the exact double value you get when you write 0.1 is to write new BigDecimal(0.1).toString().
    2. "Why does 0.1f + 0.2f == 0.3f return true?" Pretty much because you just got lucky: rounding 0.1 to the closest float representation and 0.2 to the closest float representation and adding them gets you the closest representable float to 0.3. That's not true in general, those values just happen to work.

    这篇关于Java中的浮点精度和相等性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆