“新BigDecimal(13.3D)”导致不精确的“13.3000000000000007105 ..”?

Java的BigDecimal怎么会这么痛苦呢?

 Double d = 13.3D; BigDecimal bd1 = new BigDecimal(d); BigDecimal bd2 = new BigDecimal(String.valueOf(d)); System.out.println("RESULT 1: "+bd1.toString()); System.out.println("RESULT 2: "+bd2.toString()); RESULT 1: 13.300000000000000710542735760100185871124267578125 RESULT 2: 13.3 

是否存在需要结果1的情况? 我知道Java 1.5改变了toString()方法,但这是预期的后果吗?

另外我意识到BigDecimaldoubleValue()等,但我正在使用的库有助于使用toString()而我无法改变:-(

干杯。

那么, API确实解决了构造函数BigDecimal(double val)明显的不一致性:

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

  2. 另一方面,String构造函数是完全可预测的:写入新的BigDecimal(“0.1”)会创建一个BigDecimal,它正好等于0.1,正如人们所期望的那样。 因此, 通常建议使用String构造函数优先于此构造函数。

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

故事的道德:痛苦似乎是自己造成的,只需使用new BigDecimal(String val)BigDecimal.valueOf(double val)代替=)

你的问题与BigDecimal无关,而且Double所有内容都无法准确表示13.3,因为它在内部使用了二进制分数。

所以你的错误是在第一行引入的。 第一个BigDecimal只保留它,而String.valueOf()做了一些可疑的圆形,导致第二个具有所需的内容,几乎是通过运气。

您可能想要了解浮点值的实现方式( IEEE 754-1985 )。 突然间,一切都会变得清澈透明。

这不是BigDecimal的错 – 这是double的错。 BigDecimal准确地表示d确切值。 String.valueOf仅将结果显示为几个小数位。

用二进制数类型表示的分数(即doublefloat )无法准确地存储在这些类型中。

  Double d = 13.3; BigDecimal bdNotOk = new BigDecimal(d); System.out.println("not ok: " + bdNotOk.toString()); BigDecimal bdNotOk2 = new BigDecimal(13.3); System.out.println("not ok2: " + bdNotOk2.toString()); double x = 13.3; BigDecimal ok = BigDecimal.valueOf(x); System.out.println("ok: " + ok.toString()); double y = 13.3; // pretty lame, constructor's behavior is different from valueOf static method BigDecimal bdNotOk3 = new BigDecimal(y); System.out.println("not ok3: " + bdNotOk3.toString()); BigDecimal ok2 = new BigDecimal("13.3"); System.out.println("ok2: " + ok2.toString()); Double e = 0.0; for(int i = 0; i < 10; ++i) e = e + 0.1; // some fractions cannot be accurately represented with binary System.out.println("not ok4: " + e.toString()); // should be 1 BigDecimal notOk5 = BigDecimal.valueOf(e); System.out.println("not ok5: " + notOk5.toString()); // should be 1 /* * here are some fractions that can be represented exactly in binary: * 0.5 = 0.1 = 1 / 2 * 0.25 = 0.01 = 1 / 4 * 0.75 = 0.11 = 3 / 4 * 0.125 = 0.001 = 1 / 8 */ 

输出:

 not ok: 13.300000000000000710542735760100185871124267578125 not ok2: 13.300000000000000710542735760100185871124267578125 ok: 13.3 not ok3: 13.300000000000000710542735760100185871124267578125 ok2: 13.3 not ok4: 0.9999999999999999 not ok5: 0.9999999999999999 

只需使用BigDecimal.valueOf(d)new BigDecimal(s)