`

一个JDK7的四舍五入的bug引发的思考

阅读更多

一个JDK7的四舍五入的bug引发的思考

1.背景:

今天我的 feilong-core 项目使用 jdk8 进行maven install 的时候,有一个测试类报错, 但是原先使用jdk7 进行maven install的时候却是正常通过,

issue 参见 venusdrogon/feilong-core#165

2.测试类代码如下:

    @Test
    public void testFormat32(){
        assertEquals("1.2", NumberFormatUtil.format(1.15, "#####.#", RoundingMode.HALF_EVEN));
        assertEquals("1.2", NumberFormatUtil.format(1.25, "#####.#", RoundingMode.HALF_EVEN));
        assertEquals("1.3", NumberFormatUtil.format(1.251, "#####.#", RoundingMode.HALF_EVEN));

        assertEquals("-1.2", NumberFormatUtil.format(-1.15, "#####.#", RoundingMode.HALF_EVEN));
        assertEquals("-1.2", NumberFormatUtil.format(-1.25, "#####.#", RoundingMode.HALF_EVEN));
        assertEquals("-1.3", NumberFormatUtil.format(-1.251, "#####.#", RoundingMode.HALF_EVEN));
    }


    @Test
    public void testFormat321(){
        assertEquals("1.2", NumberFormatUtil.format(1.15, "#####.#", null));
        assertEquals("1.3", NumberFormatUtil.format(1.25, "#####.#", null));
        assertEquals("1.3", NumberFormatUtil.format(1.251, "#####.#", null));

        assertEquals("-1.2", NumberFormatUtil.format(-1.15, "#####.#", null));
        assertEquals("-1.3", NumberFormatUtil.format(-1.25, "#####.#", null));
        assertEquals("-1.3", NumberFormatUtil.format(-1.251, "#####.#", null));
    }


    @Test
    public void testFormat111(){
        assertEquals("1.2", NumberFormatUtil.format(1.15, "#####.#"));
        assertEquals("1.3", NumberFormatUtil.format(1.25, "#####.#"));
        assertEquals("1.3", NumberFormatUtil.format(1.251, "#####.#"));

        assertEquals("-1.2", NumberFormatUtil.format(-1.15, "#####.#"));
        assertEquals("-1.3", NumberFormatUtil.format(-1.25, "#####.#"));
        assertEquals("-1.3", NumberFormatUtil.format(-1.251, "#####.#"));
    }

3.报错信息

    Tests run: 568, Failures: 3, Errors: 0, Skipped: 2, Time elapsed: 2.194 sec <<< FAILURE! - in com.feilong.core.FeiLongSuiteTests
    testFormat111(com.feilong.core.text.NumberFormatUtilTest)  Time elapsed: 0.009 sec  <<< FAILURE!
    org.junit.ComparisonFailure: expected:<1.[2]> but was:<1.[1]>
        at com.feilong.core.text.NumberFormatUtilTest.testFormat111(NumberFormatUtilTest.java:149)

    testFormat321(com.feilong.core.text.NumberFormatUtilTest)  Time elapsed: 0 sec  <<< FAILURE!
    org.junit.ComparisonFailure: expected:<1.[2]> but was:<1.[1]>
        at com.feilong.core.text.NumberFormatUtilTest.testFormat321(NumberFormatUtilTest.java:135)

    testFormat32(com.feilong.core.text.NumberFormatUtilTest)  Time elapsed: 0.001 sec  <<< FAILURE!
    org.junit.ComparisonFailure: expected:<1.[2]> but was:<1.[1]>
        at com.feilong.core.text.NumberFormatUtilTest.testFormat32(NumberFormatUtilTest.java:121)


    Results :

    Failed tests: 
      NumberFormatUtilTest.testFormat111:149 expected:<1.[2]> but was:<1.[1]>
      NumberFormatUtilTest.testFormat32:121 expected:<1.[2]> but was:<1.[1]>
      NumberFormatUtilTest.testFormat321:135 expected:<1.[2]> but was:<1.[1]>

    Tests run: 568, Failures: 3, Errors: 0, Skipped: 2

    [INFO] ------------------------------------------------------------------------
    [INFO] BUILD FAILURE

4.原因

经过搜索,发现

https://bugs.openjdk.java.net/browse/JDK-7131459
https://bugs.openjdk.java.net/browse/JDK-8029896
http://stackoverflow.com/questions/22797964/is-inconsistency-in-rounding-between-java-7-and-java-8-a-bug

jdk7上是bug , jdk8 修复了

image

5.思考

  • 不要使用 float 或者 double 浮点数来表述货币这样的精确数量的值,会导致舍入误差。使用浮点数来进行元和分计算会得到灾难性的后果
  • 浮点数最好用来表示象测量值这类数值,这类值从一开始就不怎么精确。(PS:一般情况在你的工作中理论上是用不到的)
  • 尽量不要用 float 或者 double ,来做 +-*/ 运算,以及format,小数请使用 BigDecimal
  • BigDecimal 的构造函数有

    • java.math.BigDecimal.BigDecimal(double)
    • java.math.BigDecimal.BigDecimal(String)

    请使用 java.math.BigDecimal.BigDecimal(String))(PS:如果你使用 sonar 进行代码扫描的话,它会给你提示和建议)

  • 比较两个 BigDecimal 大小,请使用 java.math.BigDecimal.compareTo(BigDecimal) 方法,而不要使用 java.math.BigDecimal.equals(Object)方法,

    因为

    equals()方法认为,两个表示同一个数但换算值不同(例如, 100.00 和 100.000 )的 BigDecimal 值是不相等的。
    然而, compareTo() 方法会认为这两个数是相等的,所以在从数值上比较两个 BigDecimal 值时,应该使用 compareTo() 而不是 equals() 。

    参见源码:

6.参考

分享到:
评论

相关推荐

    JDK7安装包.zip

    JDK7安装包.zip\JDK7安装包.zip\JDK7安装包.zip\JDK7安装包.zip\JDK7安装包.zip JDK7安装包.zip\JDK7安装包.zip\JDK7安装包.zip\JDK7安装包.zip\JDK7安装包.zip JDK7安装包.zip\JDK7安装包.zip\JDK7安装包.zip\JDK7...

    java-jdk-8u231-windowsx64修复bug.rar

    本版本修复 JDK的Bug1–数组切割 JDK的Bug2–三元运算符 JDK中不算Bug的Bug–ArrayList可通过构造函数传入非指定泛型的List并在get时出错

    jdk7下载下载

    jdk7j下载jdk7j下载jdk7j下载jdk7j下载jdk7j下载jdk7j下载jdk7j下载jdk7j下载jdk7j下载jdk7j下载jdk7j下载jdk7j下载jdk7j下载

    jdk7 jdk8 jdk9 jdk10 jdk11 jdk12 jdk13 jdk14 (win-64位) 百度网盘下载

    jdk7 jdk8 jdk9 jdk10 jdk11 jdk12 jdk13 jdk14 (win-64位) 资源共享

    JDK7新特性(完整篇)

    1.1 JDK7新特性&lt;一&gt;概述 . . . . . . . . . . . . . . 1.2 JDK7新特性&lt;二&gt; 语法 . . . . . . . . . . . . . 1.3 JDK7新特性&lt;三&gt; JDBC4.1 . . . . . . . . . . 1.4 JDK7新特性&lt;四&gt; NIO2.0 文件系统 . . . 1.5 JDK...

    jdk7chm,java7帮助,jdk7api,jdk1.7帮且文档

    jdk7chm,java7帮助,jdk7api,jdk1.7帮且文档,jdk7api chm,JDK(Java Development Kit)是Sun Microsystems针对Java开发员的产品。自从Java推出以来,JDK已经成为使用最广泛的Java SDK。JDK 是整个Java的核心,包括了...

    jdk-7u80-windows-x64安装包

    jdk-7u80-windows-x64安装包 jdk-7u80-windows-x64安装包 jdk-7u80-windows-x64安装包 jdk-7u80-windows-x64安装包 jdk-7u80-windows-x64安装包 jdk-7u80-windows-x64安装包 jdk-7u80-windows-x64安装包 jdk-7u80-...

    jdk7 jdk-7u80-linux-x64 网盘下载

    jdk7 jdk-7u80-linux-x64 网盘下载

    jdk-7u80最终版

    JDK1.7最终版,jdk-7u80,包含文件如下: jdk-7u80-linux-i586.gz jdk-7u80-linux-x64.tar.gz jdk-7u80-windows-i586.exe jdk-7u80-windows-x64.exe

    jdk7安装程序

    jdk7安装程序

    jdk7 免安装版 win64

    jdk7免安装版,可以正常使用,有问题可以联系我,JDK(Java Development Kit)就是Java的开发工具包,无论是开发javase,javaee,javaee.是给Java开发者必须用到的开发工具

    Java jdk7.rar

    jdk7

    JDK 开发工具包 17.0.7

    JDK 17.0.7 的主要特点 支持 Java 应用程序的跨平台性:JDK 17.0.7 支持 Windows、Linux 和 macOS 等操作系统,使开发人员能够在同一平台上开发并运行 Java 应用程序。 改进的性能和稳定性:JDK 17.0.7 包括许多性能...

    jdk7 msi 安装包

    jdk7 msi 安装包

    jdk7-aarch64-uos.tar.gz

    jdk7,openjdk7,适用于arm64、aarch64架构linux等国产化服务器,如银河麒麟V10、uos等服务器系统。 详细信息 jdk7 arm64 aarch64 。亲测可用。

    windows-java-jdk7

    jdk7安装包jdk7安装包jdk7安装包jdk7安装包jdk7安装包jdk7安装包jdk7安装包

    jdk-7u80-windows-x64.exe 【官方下载的jdk1.7、jdk7,windows 64位版】

    jdk-7u80-windows-x64.exe 【官方下载的jdk1.7、jdk7,windows 64位版】

    jdk7(Linux 平台jdk7 )

    linux平台的64位版本jdk7,官方原版,hash可匹配验证 。

    JDK7api JDKAPI

    JDK7u4的API,JDK7的帮助文档

    jdk7与jdk8

    由于上传文件不能大于110MB,下载文本里给出云盘下载link, win(jdk7,jdk8) linux(jdk7)

Global site tag (gtag.js) - Google Analytics