java - 对 DecimalFormat/RoundingMode.Down 边缘情况的功能感到困惑

标签 java floating-point decimalformat

基于this stackoverflow post ,我希望以下内容打印出 0.59 而不是 0.60。

import java.math.RoundingMode;
import java.text.DecimalFormat;

public class Test {
    public static void main(String[] args) {
        double toFormat = 0.6;
        DecimalFormat formatter = new DecimalFormat("########0.00");
        formatter.setRoundingMode(RoundingMode.DOWN);
        System.out.println(formatter.format(toFormat)); // 0.60
    }
}

最接近 0.60 的浮点表示形式是 0.59999999999999997779553950749686919152736663818359375,低于 0.6。在 Java 8 中将 DecimalFormat 设置为 RoundingMode.DOWN 时,为什么不向下舍入为 0.59?

最佳答案

因为格式化代码知道double的精度。

参见source code中的评论类 java.text.DigitList 中的方法 shouldRoundUp(...) 的:

To avoid erroneous double-rounding or truncation when converting a binary double value to text, information about the exactness of the conversion result in FloatingDecimal, as well as any rounding done, is needed in this class.

  • For the HALF_DOWN, HALF_EVEN, HALF_UP rounding rules below: In the case of formating float or double, We must take into account what FloatingDecimal has done in the binary to decimal conversion.

    Considering the tie cases, FloatingDecimal may round-up the value (returning decimal digits equal to tie when it is below), or "truncate" the value to the tie while value is above it, or provide the exact decimal digits when the binary value can be converted exactly to its decimal representation given formating rules of FloatingDecimal ( we have thus an exact decimal representation of the binary value).

    • If the double binary value was converted exactly as a decimal value, then DigitList code must apply the expected rounding rule.

    • If FloatingDecimal already rounded up the decimal value, DigitList should neither round up the value again in any of the three rounding modes above.

    • If FloatingDecimal has truncated the decimal value to an ending '5' digit, DigitList should round up the value in all of the three rounding modes above.

    This has to be considered only if digit at maximumDigits index is exactly the last one in the set of digits, otherwise there are remaining digits after that position and we don't have to consider what FloatingDecimal did.

  • Other rounding modes are not impacted by these tie cases.

  • For other numbers that are always converted to exact digits (like BigInteger, Long, ...), the passed alreadyRounded boolean have to be set to false, and allDecimalDigits has to be set to true in the upper DigitList call stack, providing the right state for those situations..

关于java - 对 DecimalFormat/RoundingMode.Down 边缘情况的功能感到困惑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46736900/

相关文章:

java - 打包java桌面应用程序(gradle)

java - 为什么 ShuffleConsumerPlugin 在映射之前没有启动?

sql-server - SQL Server 是舍入还是截断?

Java DecimalFormat 向下舍入

java - 使用 DecimalFormat Grouping java 时删除最后一个分组分隔符

java - Hibernate 标准 LEFT JOIN

java - 重写 JPA @Embedded 列上的排序行为

python - 为什么 "decimal.Decimal(' 0') < 1.0"在 Python 2.6.5 中产生 False

MySQL Math —— INTEGER 和 FLOAT 哪个更快?

Java:如何从某个字符串位置解析 double 并获取其后面的 char 的位置?