我发现DecimalFormatjava 7和java 8之间的类舍入不一致.这是我的测试用例:
import java.text.DecimalFormat;
public class DecimalFormatTest {
public static void main(String[] args) {
DecimalFormat format = (DecimalFormat) DecimalFormat.getInstance();
format.setDecimalSeparatorAlwaysShown(true);
format.setMinimumFractionDigits(1);
format.setMaximumFractionDigits(1);
System.out.println(format.format(83.65));
}
}
Run Code Online (Sandbox Code Playgroud)
在Java(TM)SE运行时环境(版本1.7.0_51-b13)中,输出为:
83.6
Run Code Online (Sandbox Code Playgroud)
在Java(TM)SE运行时环境(版本1.8.0-b132)中,输出为:
83.7
Run Code Online (Sandbox Code Playgroud)
这是一个回归错误吗?或者随着Java 8的发布,舍入规则发生了变化?
mel*_*okb 23
看起来这是JDK 7中一个长期存在的错误,最终得到修复.参见例如:
有一个计划草案,为JDK 8提供以下建议,解释了这个问题:
-------------------------------------------------- -------------------区域:核心库/ java.text
概要:JDK7的错误舍入行为已得到修复.当值非常接近准确位于格式化模式中指定的舍入位置的平局时,NumberFormat/DecimalFormat format()方法的舍入行为已更改.
不相容的性质:行为
描述:使用NumberFormat/DecimalFormat类时,以前的JDK版本的舍入行为在某些极端情况下是错误的.当使用非常接近平局的值调用format()方法时会发生这种错误行为,而使用的NumberFormat/DecimalFormat实例的模式指定的舍入位置恰好位于平局的位置.在这种情况下,发生了错误的双舍入或错误的非舍入行为.
例如,在使用默认推荐的
NumberFormatFormatAPI表单时:NumberFormat nf = java.text.NumberFormat.getInstance()后面跟着nf.format(0.8055d),值0.8055d记录在计算机中,0.80549999999999999378275106209912337362766265869140625因为此值无法以二进制格式精确表示.这里默认的舍入规则是"半连",并呼吁在JDK7格式()的结果是"0.806"一个错误的输出,而正确的结果是"0.805",因为由计算机记录在存储器值"下方"领带.对于可能由程序员选择的任何模式(非默认模式)定义的所有舍入位置,也实现了这种新行为.
RFE
7131459
Wil*_*ice 15
正如在这个问题的其他答案中所提到的,JDK 8对问题JDK-7131459中的舍入进行了有意的更改:DecimalFormat在接近平局时产生错误的format()结果.DecimalFormat
但是,这些更改引入了一个真正的错误,如JDK-8039915:错误的NumberFormat.format()HALF_UP在最后一个数字正好在舍入位置大于5时进行舍入.例如:
99.9989 -> 100.00
99.9990 -> 99.99
Run Code Online (Sandbox Code Playgroud)
简而言之,这表明一个更高的数字向下舍入,而更低的数字向上舍入的情况:(x <= y) != (round(x) <= round(y)).它似乎只影响HALF_UP舍入模式,这是在小学运算类中教授的一种舍入:总是从零开始0.5舍入.
此问题存在于Java 8的Oracle和OpenJDK版本中,并且更新了8u5,8u11,8u20,8u25和8u31.
1.8.0_40-b252015年3月3日公共GA发布8u40与JDK (发行说明)感谢Holger在这个相关问题的答案中的研究,我能够开发一个运行时补丁,我的雇主已经根据GPLv2许可条款释放了它,并带有Classpath异常1(与OpenJDK源代码相同).
补丁项目和源代码托管在GitHub上,其中包含有关此错误的更多详细信息以及可下载二进制文件的链接.该补丁在运行时工作,因此不会对磁盘上的Java文件进行任何修改,并且它应该可以安全地用于所有版本的Oracle Java> = 6且至少通过版本8(包括u40及更高版本).
1我不是律师,但我的理解是GPLv2 w/CPE允许以二进制形式进行商业用途,而GPL 不适用于组合工作.
| 归档时间: |
|
| 查看次数: |
9048 次 |
| 最近记录: |