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()
方法,但这是预期的后果吗?
我也意识到BigDecimal
有doubleValue()
等,但我正在使用的图书馆使用了toString()
并且我无法改变: - (
干杯。
答案 0 :(得分:50)
好吧,API确实解决了构造函数BigDecimal(double val)
中明显不一致的问题:
此构造函数的结果可能有些不可预测。有人可能 假设写新 Java中的BigDecimal(0.1)创建了一个 BigDecimal完全等于 0.1(未缩放值为1,刻度为1),但实际上是相等的 至 0.1000000000000000055511151231257827021181583404541015625。这是因为0.1 不能 完全代表双重(或 就此而言,作为二元分数 任何有限长度)。因此,价值 正在被传递到 构造函数不完全等于 0.1,尽管有外表。
另一方面,String构造函数是完全可预测的: 写新的BigDecimal(“0.1”)创建 一个完全等于的BigDecimal 0.1,正如人们所期望的那样。因此,一般建议使用 可以使用字符串构造函数 偏好这个。
- 醇>
当必须将double用作BigDecimal 的来源时,请注意 这个构造函数提供了精确的 转换;它没有给出相同的 结果将double转换为a 字符串使用 Double.toString(double)方法和 然后使用BigDecimal(String) 构造函数。要获得该结果,使用 静态valueOf(double)方法。
故事的道德:痛苦似乎是自己造成的,只需使用new BigDecimal(String val)
或BigDecimal.valueOf(double val)
代替=)
答案 1 :(得分:11)
您的问题与BigDecimal
以及Double
的所有内容无关,因为它在内部使用二进制分数,因此无法准确表示13.3。
所以你的错误是在第一行引入的。第一个BigDecimal
只是保留了它,而String.valueOf()
做了一些可疑的圆形,导致第二个具有所需的内容,几乎是通过运气。
答案 2 :(得分:8)
您可能想要了解浮点值的实现方式(IEEE 754-1985)。突然之间,一切都会变得清晰。
答案 3 :(得分:5)
这不是BigDecimal
的错误 - 这是double
的错误。 BigDecimal
准确表示d
的完全值。 String.valueOf
仅将结果显示为小数位。
答案 4 :(得分:3)
以二进制数字类型表示的分数(即double
,float
)无法准确存储在这些类型中。
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)
。