繁体   English   中英

DecimalFormat和定点数舍入

[英]DecimalFormat and rounding for fixed point numbers

在使用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... )之间的2082809.08058973 尽管如此, DecimalFormat在提供double参数时会向上DecimalFormat该值。

其他值向下取整:

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的格式化字符串是根据基于Double.toString()东西生成的不精确的十进制值使用半偶数舍入而舍入的,而不是所讨论的double表示的实际数学值。 当格式化的精度非常接近(或超过) double型提供的精度时,事情开始变得有些随机。

在上述所有情况下,格式化相应的BigDecimal似乎都能按预期执行舍入。

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

  • 此行为记录在某处吗?

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

    我了解编写1.0...35人们(天真吗?)期望将其舍入为1.0...4 ,但是1.0...35甚至在Java中可用的任何原始数据类型中都无法表示...

编辑:

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

这显然是Java 8中解决已知问题

无论开发人员选择哪种格式,Java 8中的DecimalFormat都应该始终正确执行舍入。 自然,与Java 7相比,这会导致行为略有不兼容-是否重要与否取决于每个应用程序的细节。

根据Java语言规范 ,Java使用IEEE 754-1985,而您(摘自IEEE754-2008的注释)

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

使用DecimalFormat setRoundingMode()来指定舍入行为。

此行为记录在某处吗?

请参见DecimalFormat的 javadoc以及RoundingModeIEEE 754-1985和JLS中的详细信息(此答案中的第一位陈述)

默认情况下,如所记录的那样,是Half Half Rounding模式。 HALF_EVEN

public static final RoundingMode HALF_EVEN

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

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM