一个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
修复了
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() 。参见源码:
相关推荐
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(Linux 平台jdk7 )"的标题明确指出这是一个适用于Linux系统的JDK7版本。 描述中提到“linux平台的64位版本jdk7,官方原版,hash可匹配验证”,这表明这个JDK7的下载来源于官方,保证了软件的原汁原味和安全性。...
JDK 7 Update 80(简称JDK 7u80)是JDK 7的一个重要更新版本,它主要针对之前版本中存在的安全漏洞进行了修复,并且进一步提升了系统的稳定性和性能。以下是JDK 7u80的一些关键更新: ##### 3.1 安全修复 - 修复了...
JDK7作为Java发展历程中的一个重要版本,引入了许多新的特性和改进,其API(Application Programming Interface)是开发者进行Java编程的基础。本文将深入解析JDK7 API中的关键知识点,旨在帮助开发者更好地理解和...
1. **多线程并行GC(Garbage Collector)优化**:JDK7引入了G1垃圾收集器,这是一个并行的、低暂停时间的垃圾收集器,旨在减少应用程序的停顿时间,提高整体性能。 2. **类型推断(Type Inference)**:Java 7的...
在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-...
JDK7-aarch64-uos.tar.gz这个压缩包文件,便是针对arm64与aarch64架构的Linux系统,尤其是针对银河麒麟V10、uos等国产服务器系统,提供了一个兼容的Java Development Kit (JDK) 版本。本文将详细探讨JDK7在Aarch64...
jdk7 jdk8 jdk9 jdk10 jdk11 jdk12 jdk13 jdk14 (win-64位) 资源共享
JDK7是Oracle公司发布的Java平台的一个重要版本,它的全称为"Java SE 7"(Java Standard Edition 7)。这个版本在2011年发布,引入了许多新特性和改进,旨在提升开发效率和增强程序性能。 1. **多语言支持**:JDK7...
JDK 7(Java Development Kit 7)是Oracle公司发布的Java开发工具包的一个版本,它包含了开发Java应用程序所需的工具、文档以及库文件等资源。JDK 7是在JDK 6的基础上进行了一系列改进与增强,引入了许多新功能和...
jdk7chm,java7帮助,jdk7api,jdk1.7帮且文档,jdk7api chm,JDK(Java Development Kit)是Sun Microsystems针对Java开发员的产品。自从Java推出以来,JDK已经成为使用最广泛的Java SDK。JDK 是整个Java的核心,包括了...
JDK7u4是Oracle公司发布的一个重要版本,其中包含了许多对Java API的增强和改进。这份API文档,即JDK7u4的API,是开发者理解和使用这个版本JDK的重要参考资料,它详尽地介绍了各类类库、接口、方法和异常等元素,为...
在这个特定的压缩包中,我们找到了"jdk-7u80-windows-x64.exe",这正是JDK 1.7的64位版本,适用于Windows操作系统。这个版本的JDK是Java 7的更新版本,编号为u80,代表Update 80,意味着它包含了自初始发布以来的...
Java JDK 7是Java开发工具包的一个重要版本,它的全称是Java Development Kit,是用于构建和运行Java应用程序的关键组件。这个PDF学习笔记是开发者深入理解JDK 7特性和功能的重要参考资料。以下是对Java JDK 7的一些...
JDK 7,也被称为JDK 1.7,是Oracle公司发布的一个重要版本,它引入了许多新特性,优化了性能,并修复了大量的bug。通过深入学习JDK 7的源代码,开发者可以更好地理解Java语言的工作原理,提高编程技能,并对新旧版本...
JDK 7u80作为Java 7的一个更新,主要目的是修复之前版本中的已知问题,提高稳定性和性能。对于开发者而言,安装这个版本的JDK意味着可以利用Java 7的所有特性和改进,同时享受最新的安全更新和bug修复。 在Windows...
jdk7 jdk8 jdk9 jdk10 jdk11 jdk12 jdk13 jdk14 (linux-rpm 64位) 资源共享
首先,JDK7是Java平台的一个重大更新,正式版本为7u40,它引入了多项新特性,如Try-with-resources语句,用于自动管理资源关闭,避免资源泄露;多 catches 语句,允许在一个catch块中捕获多种类型的异常;钻石操作符...
JDK 7是Java的一个重要版本,它在JDK 6的基础上引入了许多新特性和改进,提升了开发效率和程序性能。 标题中的"jdk 7 32位免安装版"指的是这个压缩包包含的是适用于32位操作系统的Java 7开发工具包,并且是免安装...