为什么新的BigDecimal("0.015").compareTo(new BigDecimal(0.015))返回-1?

Gli*_*ide 15 java bigdecimal

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

Rei*_*eus 20

由于浮点运算的不精确性,它们并不完全相等

System.out.println(new BigDecimal(0.015));
Run Code Online (Sandbox Code Playgroud)

显示器

0.01499999999999999944488848768742172978818416595458984375
Run Code Online (Sandbox Code Playgroud)

  • @KyleStrand:关键在于你必须传递_decimal数字in_,然后将`new BigDecimal(0.015)`存储`0.015`作为`double` - _not_一个十进制数 - 在它变为`BigDecimal`之前.你必须把它作为`String`传递. (5认同)
  • @Glide:如果你期望新的BigDecimal(0.015)等于新的BigDecimal("0.015"),那么你应该期待错误,你应该期望你不得不期待一些不同的东西. (4认同)
  • 你不应该指望它们是平等的.无论何时使用浮点运算,您都应该意识到会发生这类错误. (3认同)
  • @LouisWasserman Er .....我(作为一个非Java程序员,因此是一个局外人)的印象是'BigDecimal`的*整点*是准确地表示*十进制数*.哎呀,[文档](http://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html)甚至说*任意精度*十进制数!如果`0.015`没有以独特的方式表示,那么`BigDecimal`类应该是多么可用? (3认同)
  • 我想我唯一的抱怨是,"BigDecimal"甚至首先提供了来自`double`的构造函数. (2认同)

Pau*_*and 7

为了扩展@Reimeus 的答案,BigDecimal的各种构造函数接受不同类型的输入.所述浮点构造,采取一个浮点作为输入,并由于漂浮的方式的限制/双打被存储,这些只能存储准确是2的幂的值.

因此,例如,可以精确地表示2 -2或0.25.0.875是(2 -1 + 2 -2 + 2 -3),因此它也可以准确地表示.只要数量可以用幂的总和来表示,其中上限和下限相差不超过53,那么数字可以精确地表示.绝大多数数字都不符合这种模式!

特别地,0.15不是2的幂,也不是2的幂的和,因此表示不准确.

另一方面,字符串构造函数通过在内部使用不同的格式来存储数字,从而准确地存储它.因此,当你比较两者时,他们会比较不同.


Boa*_*ann 5

A double无法准确表示该值0.015.它在64位二进制位中可以表示的最接近的值是0.01499999999999999944488848768742172978818416595458984375.构造函数new BigDecimal(double)旨在保留double参数的精确值,这绝不是完全正确的0.015.因此,你的比较结果.

但是,如果您显示该double值,例如:

System.out.println(0.01499999999999999944488848768742172978818416595458984375);
Run Code Online (Sandbox Code Playgroud)

它输出0.015- 暗示了一种解决方法.将a转换double为a会String选择所需的最短十进制表示,以区别于其他可能的double值.

因此,如果您BigDecimaldouble's String表示创建一个,它将具有更多的值,如您所期望的那样.这种比较是正确的:

new BigDecimal(Double.toString(0.015)).equals(new BigDecimal("0.015"))
Run Code Online (Sandbox Code Playgroud)

实际上,该方法BigDecimal.valueOf(double)正是出于此目的,因此您可以将上述内容缩短为:

BigDecimal.valueOf(0.015).equals(new BigDecimal("0.015"))
Run Code Online (Sandbox Code Playgroud)

new BigDecimal(double)仅当您的目的是保留参数的精确二进制值时,才应使用构造函数.否则,打电话BigDecimal.valueOf(double),其文件说:

这通常是将double(或float)转换为a 的首选方式BigDecimal.

或者,String如果可以的话,使用a 并double完全避免细微之处.