为什么new BigDecimal("0.015").compareTo(new BigDecimal(0.015))
会返回-1?
如果我希望这两者相等,是否有另一种方法来比较它们?
答案 0 :(得分:20)
由于浮点运算的不精确性,它们并不完全相等
System.out.println(new BigDecimal(0.015));
显示器
0.01499999999999999944488848768742172978818416595458984375
答案 1 :(得分:7)
要扩展@Reimeus中的answer,BigDecimal的各种构造函数接受不同类型的输入。 浮点构造函数,将浮点作为输入,并且由于存储浮点/双精度的方式的限制,这些只能精确存储2的幂的值。
因此,例如,2 -2或0.25可以精确表示。 0.875是(2 -1 + 2 -2 + 2 -3),因此它也可以准确地表示。只要数量可以用幂的总和来表示,其中上限和下限相差不超过53,那么数字可以精确地表示。绝大多数数字都不符合这种模式!
特别是,0.15不是2的幂,也不是2的幂的总和,因此表示不准确。
另一方面,字符串构造函数通过在内部使用不同的格式来存储数字,从而准确地存储它。因此,当你比较两者时,他们会比较不同。
答案 2 :(得分:5)
double
无法准确表示值0.015
。它在64位二进制位中可以表示的最接近的值是0.01499999999999999944488848768742172978818416595458984375
。构造函数new BigDecimal(double)
旨在保留double
参数的精确值,该参数永远不能完全0.015
。因此,你的比较结果。
但是,如果您显示double
值,例如:
System.out.println(0.01499999999999999944488848768742172978818416595458984375);
它输出0.015
- 暗示了解决方法。 Converting a double
to a String
选择所需的最短十进制表示,以区别于其他可能的double
值。
因此,如果您从BigDecimal
的{{1}}表示中创建double
,则其值会更符合您的预期。这种比较是正确的:
String
事实上,方法BigDecimal.valueOf(double)
正是出于此目的,因此您可以将上述内容缩短为:
new BigDecimal(Double.toString(0.015)).equals(new BigDecimal("0.015"))
只有当您的目的是保留参数的精确二进制值时,才应使用BigDecimal.valueOf(0.015).equals(new BigDecimal("0.015"))
构造函数。否则,请致电new BigDecimal(double)
,其文档说明:
这通常是将
BigDecimal.valueOf(double)
(或double
)转换为float
的首选方法。
或,如果可以,请使用BigDecimal
并完全避免String
的微妙之处。
答案 3 :(得分:4)
这里实际发生的是:
0.015
是原始的双倍。这意味着一旦你写它,它已经不再是0.015,而是0.0149...
。 编译器将其存储为字节码中的二进制表示。BigDecimal
用于存储完全给予的任何内容。在这种情况下,0.0149...
BigDecimal
还可以将字符串解析为完全表示形式。在这种情况下,"0.015"
将被解析为0.015
。即使double
无法代表该数字,BigDecimal
也可以每当使用BigDecimal
时,请注意以前使用的类型。 String
,int
,long
将保持准确。 float
和double
有通常的精确警告。