基于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的精度。

请参见类shouldRoundUp(...)中方法java.text.DigitListsource code中的注释:


  为了避免转换时错误的双舍入或截断
  文本的二进制双精度值,有关准确性的信息
  转换结果在FloatingDecimal中的值,以及任何
  在该类中需要四舍五入。
  
  
  对于以下HALF_DOWN,HALF_EVEN,HALF_UP舍入规则:
  在格式化float或double的情况下,我们必须考虑
  在二进制到十进制中说明FloatingDecimal做了什么
  转换。
  
  考虑平局情况,FloatingDecimal可能会将
  值(低于此值时,返回等于tie的十进制数字),
  或将值“截断”到领带之上,而值超过领带,
  或在二进制值可以是时提供准确的十进制数字
  在给定格式的情况下,精确地转换为其十进制表示形式
  FloatingDecimal的规则(因此,我们有一个精确的十进制
  二进制值的表示形式)。
  
  
  如果将双二进制值完全转换为十进制数
  值,则DigitList代码必须应用预期的舍入
  规则。
  如果FloatingDecimal已经舍入了十进制值,
  DigitList不应在以下任何一个中再次舍入该值
  上面的三种取整模式。
  如果FloatingDecimal已将十进制值截断为
  以“ 5”结尾的数字,DigitList应将以下值四舍五入
  上面所有三个舍入模式。
  
  
  仅当数字在maximumDigits索引处时才必须考虑这一点
  恰好是一组数字中的最后一个,否则有
  该位置之后的剩余数字,我们不必考虑
  FloatingDecimal做了什么。
  其他舍入模式不受这些平局情况的影响。
  对于总是转换为精确数字的其他数字
  (例如BigInteger,Long等),则传递的hasRounded布尔值
  必须设置为false,并且allDecimalDigits必须设置为
  在上层DigitList调用堆栈中为true,提供正确的状态
  对于那些情况..

09-28 11:54