`

一个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...

    JDK7免安装解压包

    JDK7是Java语言的一个重要版本,它在JDK6的基础上引入了许多新特性、改进和优化。在这个“JDK7免安装解压包”中,用户无需进行传统意义上的安装过程,只需将压缩包解压到任意位置,并配置相应的环境变量,就能开始...

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

    JDK 7 Update 80(简称JDK 7u80)是JDK 7的一个重要更新版本,它主要针对之前版本中存在的安全漏洞进行了修复,并且进一步提升了系统的稳定性和性能。以下是JDK 7u80的一些关键更新: ##### 3.1 安全修复 - 修复了...

    jdk7api帮助文档

    JDK7作为Java发展历程中的一个重要版本,引入了许多新的特性和改进,其API(Application Programming Interface)是开发者进行Java编程的基础。本文将深入解析JDK7 API中的关键知识点,旨在帮助开发者更好地理解和...

    JDK7 Windows32位

    1. **多线程并行GC(Garbage Collector)优化**:JDK7引入了G1垃圾收集器,这是一个并行的、低暂停时间的垃圾收集器,旨在减少应用程序的停顿时间,提高整体性能。 2. **类型推断(Type Inference)**:Java 7的...

    ARM64架构下的jdk7,适配最新架构,陈年代码

    在ARM64架构下,JDK 7可能包括对ARM...此外,还有其他社区和开发者为ARM64架构提供了JDK 7的构建版本,例如Arch Linux ARM提供了jdk7-openjdk 7.u261_2.6.22-1包,这是一个OpenJDK Java 7开发工具包,适用于aarch64架构

    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 jdk8 jdk9 jdk10 jdk11 jdk12 jdk13 jdk14 (win-64位) 百度网盘下载

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

    jdk7-aarch64-uos.tar.gz

    JDK7-aarch64-uos.tar.gz这个压缩包文件,便是针对arm64与aarch64架构的Linux系统,尤其是针对银河麒麟V10、uos等国产服务器系统,提供了一个兼容的Java Development Kit (JDK) 版本。本文将详细探讨JDK7在Aarch64...

    jdk7下载下载

    JDK7是Oracle公司发布的Java平台的一个重要版本,它的全称为"Java SE 7"(Java Standard Edition 7)。这个版本在2011年发布,引入了许多新特性和改进,旨在提升开发效率和增强程序性能。 1. **多语言支持**:JDK7...

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

    JDK 7(Java Development Kit 7)是Oracle公司发布的Java开发工具包的一个版本,它包含了开发Java应用程序所需的工具、文档以及库文件等资源。JDK 7是在JDK 6的基础上进行了一系列改进与增强,引入了许多新功能和...

    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的核心,包括了...

    JDK7api JDKAPI

    JDK7u4是Oracle公司发布的一个重要版本,其中包含了许多对Java API的增强和改进。这份API文档,即JDK7u4的API,是开发者理解和使用这个版本JDK的重要参考资料,它详尽地介绍了各类类库、接口、方法和异常等元素,为...

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

    在这个特定的压缩包中,我们找到了"jdk-7u80-windows-x64.exe",这正是JDK 1.7的64位版本,适用于Windows操作系统。这个版本的JDK是Java 7的更新版本,编号为u80,代表Update 80,意味着它包含了自初始发布以来的...

    Java JDK 7学习笔记 PDF

    Java JDK 7是Java开发工具包的一个重要版本,它的全称是Java Development Kit,是用于构建和运行Java应用程序的关键组件。这个PDF学习笔记是开发者深入理解JDK 7特性和功能的重要参考资料。以下是对Java JDK 7的一些...

    jdk7源代码

    JDK 7,也被称为JDK 1.7,是Oracle公司发布的一个重要版本,它引入了许多新特性,优化了性能,并修复了大量的bug。通过深入学习JDK 7的源代码,开发者可以更好地理解Java语言的工作原理,提高编程技能,并对新旧版本...

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

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

    jdk-7u80-windows-x64.zip

    JDK 7u80作为Java 7的一个更新,主要目的是修复之前版本中的已知问题,提高稳定性和性能。对于开发者而言,安装这个版本的JDK意味着可以利用Java 7的所有特性和改进,同时享受最新的安全更新和bug修复。 在Windows...

    jdk 7 32位免安装版

    JDK 7是Java的一个重要版本,它在JDK 6的基础上引入了许多新特性和改进,提升了开发效率和程序性能。 标题中的"jdk 7 32位免安装版"指的是这个压缩包包含的是适用于32位操作系统的Java 7开发工具包,并且是免安装...

    JDK 7 下载

    1. **多捕获能力**:允许在一个catch块中捕获多个异常类型。 2. **字符串连接操作**:在字符串拼接时使用了StringBuilder而非String,从而提高了性能。 3. **二进制整数文字**:支持二进制整数文字,如0b1010表示十...

Global site tag (gtag.js) - Google Analytics