BigDecimal-使用 new 或 valueOf

我找到了两种从双 D 中提取 BigDecimal 对象的方法。

  1. new BigDecimal(d)
  2. BigDecimal.valueOf(d)

哪种方法更好? valueOf会创建一个新对象吗?

一般来说(不仅仅是 BigDecimal) ,推荐使用什么-new 还是 valueOf?

131990 次浏览

基本上 valueOf (double val)就是这样做的:

return new BigDecimal(Double.toString(val));

因此-> yep,将创建一个新对象:)。

一般来说,我认为这取决于您的编码风格。如果两者是相同的结果,我不会将 value Of 和“ new”混合。

这是两个独立的问题: “我应该为 BigDecimal使用什么?”和“我一般做什么?”

对于 BigDecimal: 这有点棘手,因为它们是 不要做同样的事情BigDecimal.valueOf(double)将使用传入的 double值的 < em > 规范 String表示 来实例化 BigDecimal对象。换句话说: BigDecimal对象的值将是执行 System.out.println(d)时所看到的值。

但是,如果使用 new BigDecimal(d),那么 BigDecimal将尝试表示 double尽可能准确。这将导致 通常存储的数字比你想要的多得多。严格地说,它比 valueOf()更正确,但是它的直观性要差得多。

在 JavaDoc 中有一个很好的解释:

此构造函数的结果可能有些不可预测。有人可能会假设用 Java 编写 new BigDecimal(0.1)创建的 BigDecimal恰好等于0.1(未缩放值为1,缩放值为1) ,但它实际上等于0.100000000000000551151231257827021181583404541015625。这是因为0.1不能精确地表示为 double(或者,就此而言,作为任何有限长度的二进制分数)。因此,传递给构造函数的值并不完全等于0.1,尽管外观如此。

一般来说,如果结果是一样的(即不是在 BigDecimal的情况下,而是在大多数其他情况下) ,那么 valueOf()应该是首选的: 它可以对公共值进行缓存(就像在 Integer.valueOf()上看到的那样) ,它甚至可以改变缓存行为,而不需要改变调用者。new一直都是实例化一个新值,即使不是必需的(最好的例子: new Boolean(true)Boolean.valueOf(true))。

如果您使用 BigDecimal对象来存储货币值,那么我强烈建议您在 没有的计算中使用任何双精度值。

正如在另一个答案中提到的,存在已知的双值准确性问题,这些问题将回来困扰您的大时间。

一旦你克服了这一点,你问题的答案就很简单了。始终使用带 String 值的构造函数方法作为构造函数的参数,因为 String没有 valueOf方法。

如果你想要证据,试试下面的方法:

BigDecimal bd1 = new BigDecimal(0.01);
BigDecimal bd2 = new BigDecimal("0.01");
System.out.println("bd1 = " + bd1);
System.out.println("bd2 = " + bd2);

您将得到以下输出:

bd1 = 0.01000000000000000020816681711721685132943093776702880859375
bd2 = 0.01

再看看这个 相关问题

前言

为什么我们要讨论浮点类型、数字和算术?很简单。我们以10为基数,但机器以2为基数。

BigDecimal-需要精确的表示(不是近似值)

如果您使用的是 BigDecimal,这意味着您需要 0.1和其他十的负幂的精确表示(通常您要处理的是金钱或涉及小数的算术)。

Double 意味着麻烦(就 BigDecimal 而言)

然后,如果您发现自己必须使用 BigDecimal操作 double(或 float)值,那么您就遇到了双重麻烦,因为不可能在基数2中将 0.1表示为 double。机器“存储”双倍(IEEE-754浮点运算标准)作为基数2。如果你感兴趣的话,给你是一篇关于真实情况的好文章。).邓肯的回答说明了我想说的,什么该做,什么不该做。

任何你认为可以精确存储0.1的编程语言实际上都不是,它只是一个近似值。

System.out.println(0.1d);
//Prints 0.1 or so you think ;-)


//If you are not convinced, try this:
double x = 1.1; double y = 1.0;
if (x-y == 0.1) {// print true } else {// print false}


//or perhaps this:
double amount1 = 2.15;
double amount2 = 1.10;
System.out.println("Difference: " + (amount1 - amount2));

例子

  double smallD = 0.0001;
double smallDNoScientificNotation = 0.001; //>= 10E-3
double normalD = 10.345678;
double bigDNoScientificNotation = 1234567.123456789; //<=10E7
double bigD = 56_789_123_456_789.123456789;


//double
System.out.println(smallD); //1.0E-4, computerized scientific notation, this is how Double toString works
System.out.println(smallDNoScientificNotation); //0.001, OK
System.out.println(normalD); //10.345678, OK
System.out.println(bigDNoScientificNotation); //1234567.123456789, OK
System.out.println(bigD); //5.6789123456789125E13, computerized scientific notation, this is how Double toString works
  

//new BigDecimal(double): not OK, don't use! Attempting to representing the base-2 representation as accurately as possible
System.out.println(new BigDecimal(smallD)); //0.000100000000000000004792173602385929598312941379845142364501953125
System.out.println(new BigDecimal(smallDNoScientificNotation)); //0.001000000000000000020816681711721685132943093776702880859375
System.out.println(new BigDecimal(normalD)); //10.34567799999999948568074614740908145904541015625
System.out.println(new BigDecimal(bigDNoScientificNotation)); //1234567.12345678894780576229095458984375
System.out.println(new BigDecimal(bigD)); //56789123456789.125
  

//BigDecimal.valueOf (Dont use if the range is >= 10E-3, >= 10E7), under the hood it's using Double.toString
System.out.println(BigDecimal.valueOf(smallD)); //0.00010 - notice the extra 0, stemming from 1.0E-4
System.out.println(BigDecimal.valueOf(smallDNoScientificNotation)); //0.001
System.out.println(BigDecimal.valueOf(normalD)); //10.345678
System.out.println(BigDecimal.valueOf(bigDNoScientificNotation)); //1234567.123456789
System.out.println(BigDecimal.valueOf(bigD)); //56789123456789.125 //loss of accuracy

电脑科学记数法 -更多 给你

奖励1-陷阱

给你

奖励2-有效的 Java 第三版(Joshua Bloch)

项目60: 避免浮动或双,如果确切的答案是必要的

Float 和 double 类型特别不适合货币计算,因为它不可能精确地表示0.1(或任何其他10的负幂)为 float 或 double。
:
然而,使用 BigDecimal 有两个缺点: 它比使用基元算术类型方便得多,而且速度慢得多。如果你只是在解决一个简单的问题,后者的缺点是无关紧要的,但是前者可能会惹恼你。
:
使用 BigDecimal 的另一种方法是使用 int 或 long,具体取决于所涉及的数量,并自己跟踪小数点。在这个示例中,显而易见的方法是以美分为单位进行所有计算。

对于有数学天赋的人来说,可以增加阅读量; -)

计算机科学家应该知道的浮点数算法