繁体   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