为什么新的BigDecimal(“0.015”)。compareTo(new BigDecimal(0.015))返回-1?

时间:2015-09-28 20:32:46

标签: java bigdecimal

为什么new BigDecimal("0.015").compareTo(new BigDecimal(0.015))会返回-1? 如果我希望这两者相等,是否有另一种方法来比较它们?

4 个答案:

答案 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时,请注意以前使用的类型。 Stringintlong将保持准确。 floatdouble有通常的精确警告。