DecimalFormat和舍入为定点数

时间:2013-02-17 13:05:29

标签: java precision floating-accuracy decimalformat

在使用DecimalFormat时,我对使用定点模式舍入数字时的行为感到困惑。为了使事情更具体:

double n = 2082809.080589735D;

// Output the exact value of n
System.out.println("value:       " + new BigDecimal(n).toPlainString());

System.out.println("double:      " + n);

DecimalFormat format = new DecimalFormat("0.00000000");

System.out.println("format:      " + format.format(n));
System.out.println("format (BD): " + format.format(new BigDecimal(n)));

此代码段的输出为:

value:       2082809.080589734949171543121337890625
double:      2082809.080589735
format:      2082809.08058974
format (BD): 2082809.08058973

从第一个输出行我们注意到实际值低于 2082809.080589732082809.08058974...49...)之间的中间点。尽管如此,DecimalFormat在提供double参数时会向上舍入值。

其他值向下舍入:

value:       261285.2738465850125066936016082763671875
double:      261285.273846585
format:      261285.27384658
format (BD): 261285.27384659

在所有情况下都不会发生这种情况:

value:       0.080589734949171543121337890625
double:      0.08058973494917154
format:      0.08058973
format (BD): 0.08058973

value:       0.2738465850125066936016082763671875
double:      0.2738465850125067
format:      0.27384659
format (BD): 0.27384659

在我看来,double的格式化字符串是使用half-even rounding舍入的,基于使用Double.toString()行的内容生成的不精确的十进制值,而不是实际的数学由double代表的值。当格式化的精度非常接近(或大于)double类型提供的精度时,事情开始变得有些随机。

在上面列出的所有情况中,格式化相应的BigDecimal似乎按预期执行舍入。

在这种情况下,我无法找到任何描述DecimalFormat正确行为的规范。

  • 这种行为是否记录在某处?

  • 从正确的角度来看,不会将实际数学值四舍五入?

    我理解编写1.0...35的人会(天真地?)期望它被舍入到1.0...4,但1.0...35甚至可能无法在Java中可用的任何原始数据类型中表示。 ..

修改

我已向甲骨文提交了一份报告 - 希望他们能够解决或澄清此问题。

3 个答案:

答案 0 :(得分:1)

这显然是known issue fixed in Java 8

无论开发人员选择何种格式,Java 8中的

DecimalFormat都应该始终正确执行舍入。当然,与Java 7相比,这会导致轻微的不兼容行为 - 这是否重要取决于每个应用程序的具体情况。

答案 1 :(得分:0)

根据Java Language Specification,java使用IEEE 754 - 1985,而您(来自IEEE754 - 2008的评论)

  

浮点类型是float和double,它们在概念上是   与单精度32位和双精度相关联   64位格式IEEE 754值和IEEE中规定的操作   二进制浮点运算标准,ANSI / IEEE标准   754-1985(IEEE,纽约)。

使用setRoundingMode()的{​​{1}}来指定舍入行为。

  

这种行为是否记录在某处?

请参阅DecimalFormat的javadoc和RoundingMode中的详细信息 在IEEE 754 - 1985和JLS(本回答中的第一位政治家)

默认情况下,记录为半均匀舍入模式。 HALF_EVEN

DecimalFormat
  

舍入模式向“最近邻居”舍入,除非两者都有   邻居是等距的,在这种情况下,是向着均匀的   邻居。如果左边的数字,则表现为RoundingMode.HALF_UP   被丢弃的部分是奇数;表现得像   RoundingMode.HALF_DOWN如果它是偶数。请注意,这是四舍五入   应用时统计上最小化累积误差的模式   反复进行一系列的计算。它有时被称为   “银行家的四舍五入”,主要用于美国。这四舍五入   mode类似于用于float和double的舍入策略   Java中的算术。

答案 2 :(得分:0)

看起来这可能是由于双舍入。

标记为“double”的输出看起来像是正确舍入到16位数。标记为“格式”的输出看起来像是从16位数值舍入(舍入一半到偶数)。

(我需要查看更多示例来验证这一点。)