我偶然发现了scala中的内容(也许仅适用于我) . 总之,如果我们有一个BigDecimal(比如 val a = BigDecimal(someValue)
,其中 someValue
是十进制字符串)操作的结果
N * a / N == a
不会总是产生 true
. 我想它与BigDecimals上的任何操作有关 . 我知道在scala中创建的BigDecimals默认MathContext设置为 DECIMAL128
( HALF_EVEN
舍入,精度等于34) . 我在小数点上发现了这样的行为,点数后超过30位
我的问题是我得到这样的结果的原因 . 我可以以某种方式控制它们吗?
example
-0.007633587786259541984732824427480916
1 回答
正如之前的评论已经指出的那样,无法用无理数来避免这种情况 . 这是因为无法使用标准数字类型(如果有的话)表示无理数 . 由于我没有无理数的例子(即使PI限于固定的数字位数,因此可以表示为2个整数的商,使其合理),我将使用重复小数来说明问题 . 我将
N*a/N
改为a/N*N
因为它用整数表示问题更好,但它们是等价的:正如您在上面的示例中所看到的,您可以使用尽可能多的小数位和任何舍入模式,但结果永远不会等于1.(尽管每次操作可以使用不同的舍入模式获得1,即
BigDecimal(3, roundHalfEven) * (BigDecimal(1, roundUp) / 3)
)控制数字比较可以做的一件事是在执行算术运算时使用更高的精度,并在比较时舍入到所需的(更低)精度:
在上面的示例中,最后一个表达式的计算结果为
true
.UPDATE
要回答你的评论,虽然BigDecimal是任意精度,它仍然受到精度的限制 . 它可以是34或者它可以是1000000(如果你有足够的内存) . BigDecimal不知道
1 / 3
是0.33<repeating>
. 如果你考虑分裂如何工作,那么's no way for BigDecimal to conclusively know that it'重复而不执行无限小数位的除法 . 但由于精度为2表示它可以在2位小数后停止分割,因此它只知道1 / 3
是0.33
.