在使用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.08058973
和2082809.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中可用的任何原始数据类型中表示。 ..
修改
我已向甲骨文提交了一份报告 - 希望他们能够解决或澄清此问题。
答案 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位数值舍入(舍入一半到偶数)。
(我需要查看更多示例来验证这一点。)