繁体   English   中英

为什么不推荐使用Java的“新BigDecimal(double)”?

[英]Why hasn't Java's “new BigDecimal(double)” been deprecated?

BigDecimal的构造函数

此构造函数的结果可能无法预测。 可以假设用Java编写新的BigDecimal(0.1)会创建一个BigDecimal,它精确地等于0.1(未缩放的值1,小数位为1),但实际上等于0.1000000000000000055511511231257827021181583404541015625。 这是因为0.1无法精确表示为双精度(或就此而言,表示为任何有限长度的二进制分数)。 因此,尽管出现,但是传递给构造函数的值并不完全等于0.1。

另一方面,String构造函数是完全可预测的:就像期望的那样,编写新的BigDecimal(“ 0.1”)会创建一个完全等于0.1的BigDecimal。 因此,通常建议优先使用String构造函数。

当必须将double用作BigDecimal的源时,请注意,此构造函数提供了精确的转换。 它与使用Double.toString(double)方法然后使用BigDecimal(String)构造函数将double转换为String的结果不同。 要获得该结果,请使用静态valueOf(double)方法。

那么,为什么他们不只是弃用它,而将功能更改为valueOf(double)呢? 产生不可预测的价值的意义何在?

这是完全可以预见的。 您将准确获得构造函数参数中提供的值。 正如您所引用的,对于双字面量0.1 “,传递给构造函数的值不完全等于0.1 ”。 构造函数如实地选择传入的值。

该程序说明了new BigDecimal(double)构造函数的实际用法。 目的是显示精确结果的范围,该范围将舍入到给定的两倍。 这取决于能否获得具有double精确值的BigDecimal。

import java.math.BigDecimal;

public class Test {
  public static void main(String[] args) {
    System.out.println(range(1.0));
    System.out.println(range(Math.nextUp(1.0)));
    System.out.println(range(Math.PI));
  }

  private static String range(double d){
    BigDecimal down = new BigDecimal(Math.nextDown(d));
    BigDecimal up = new BigDecimal(Math.nextUp(d));
    BigDecimal bd = new BigDecimal(d);
    BigDecimal halfUp = midPoint(bd, up);
    BigDecimal halfDown = midPoint(down, bd);
    Boolean isEven = (Double.doubleToLongBits(d) & 1) == 0;
    if(isEven){
      return "[" + halfDown + "," + halfUp + "]";
    } else {
      return "(" + halfDown + "," + halfUp + ")";      
    }
  }

  private static BigDecimal midPoint(BigDecimal low, BigDecimal high){
    return low.add(high).divide(BigDecimal.valueOf(2));
  }
}

暂无
暂无

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

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