1

在使用 时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

在我看来,a 的格式化字符串double是使用半偶数舍入舍入的,该舍入基于一个不精确的十进制值,该十进制值是由 的行产生的Double.toString(),而不是所讨论的实际数学值double。当格式化的精度非常接近(或超过)double类型提供的精度时,事情开始变得有些随机。

在上面介绍的所有情况下,格式化相应的BigDecimal似乎可以按预期执行舍入。

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

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

  • 从正确性的角度来看,将实际数学值四舍五入不是更可取吗?

    我知道写作的人1.0...35会(天真地?)期望它被四舍五入1.0...4,但1.0...35甚至可能无法用 Java 中可用的任何原始数据类型表示......

编辑:

我已经向 Oracle 提交了一份报告——希望他们能够解决或澄清这个问题。

4

3 回答 3

1

这显然是已在 Java 8 中修复的已知问题

DecimalFormat在 Java 8 中,无论开发人员选择何种格式,都应该始终正确执行舍入。自然,与 Java 7 相比,这会导致稍微不兼容的行为——这是否重要取决于每个应用程序的具体情况。

于 2014-03-18T22:39:08.050 回答
0

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

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

用于指定舍入行为setRoundingMode()DecimalFormat

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

请参阅DecimalFormat的javadoc以及RoundingModeIEEE 754 - 1985和 JLS 中的详细信息(此答案中的第一个声明)

默认情况下,如文档所述,是半偶数舍入模式。半偶数

public static final RoundingMode HALF_EVEN

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

于 2013-02-17T13:15:13.660 回答
0

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

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

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

于 2013-02-18T15:56:16.080 回答