【问题标题】:How to properly truncate a double如何正确截断双精度
【发布时间】:2013-09-21 20:33:13
【问题描述】:

如何在 Java 中正确截断双精度数,例如 1.99999999999999999 总是被截断为 1,而不是像下面的示例中那样四舍五入为 2。

    double d1 = 1.999999999999999999;
    double d2 = 1.0; 
    long i1 = (long)Math.floor(d1);
    long i2 = (long)Math.floor(d2);
    System.out.println("i1="+i1 + " i2="+i2); //i1 == 2

在此处运行示例:http://www.browxy.com/SubmittedCode/42603

解决方案

使用具有任意精度的BigDecimal

BigDecimal bd = new BigDecimal("0.9999999999999999999999999999");
bd = bd.setScale(0, BigDecimal.ROUND_DOWN); //truncate

【问题讨论】:

标签: java precision truncate


【解决方案1】:

1.99999999999999999 没有四舍五入到2,它是 2。

System.out.println(1.999999999999999999);      // 2
System.out.println(1.999999999999999999 == 2); // true

浮点数并不是无限精确的。 Java 使用的存储格式 (IEEE double) 中没有足够的位来区分 1.999999999999999999 和 2。

如果您需要更高的准确性,请尝试其他数字格式,例如 BigDecimal。

【讨论】:

  • BigDecimal 似乎也无法处理这么高的精度 - 请参阅此处browxy.com/SubmittedCode/42606
  • @volting BigDecimal 可以将 new BigDecimal("1.999999999999999999") 与两个区分开来,准确表示,并正确打印。引用的文章使用 Double 而不是 BigDecimal 来解析字符串,因此新的 BigDecimal 只能有一个可以用 double 精确表示的值。
【解决方案2】:

我认为您的 d1 精度太高,无法表示为双精度。

如果您将d1 直接打印到 System.out,您会得到2.0。

所以对floor 或round 的任何调用都无效。

如果您需要这样的精度,您应该选择BigDecimal。

【讨论】:

    【解决方案3】:

    部分示例解释here

    Documentation

    double d1 = 1.999999999999999999;
    double d2 = 1.0; 
    long i1 = (long)Math.round(d1);
    long i2 = (long)Math.floor(d2);
    
    System.out.println("i1="+i1 + " i2="+i2);
    

    那么输出会是

    i1=2 i2=1
    

    【讨论】:

    • 他不想要 2 和 1,他想要 1 和 1。
    • 他只是在解释他们的行为,而不是直接给出答案。不需要反对票
    • 嘿,它没有回答问题。
    • @redFIVE 但它没有回答问题,而且通常具有误导性。问题中的代码已经是 OP 想要做的(顺便说一句,它是正确的),它只是没有按预期工作。这完全是另外一回事。
    猜你喜欢
    • 2017-10-02
    • 1970-01-01
    • 1970-01-01
    • 2019-03-13
    • 1970-01-01
    • 1970-01-01
    • 2017-12-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多