gpt4 book ai didi

java - Scala 中的 BigDecimal

转载 作者:塔克拉玛干 更新时间:2023-11-02 08:16:23 28 4
gpt4 key购买 nike

我在 scala 中偶然发现了有趣的东西(也许只对我有用)。简而言之,如果我们有一个 BigDecimal(假设 val a = BigDecimal(someValue) 其中 someValue 是十进制字符串)操作的结果

N * a / N == a

不会总是产生 true。我想它与 BigDecimals 上的任何操作有关。我知道在 scala 中,BigDecimals 是在默认 MathContext 设置为 DECIMAL128(HALF_EVEN 舍入和精度等于 34)的情况下创建的。我在点后超过 30 位的小数上发现了这种行为

我的问题是为什么会得到这样的结果。我能以某种方式控制它们吗?

示例

-0.007633587786259541984732824427480916

最佳答案

正如之前的评论已经指出的那样,这对于无理数来说是不可避免的。这是因为无法使用标准数字类型(如果有的话)来表示无理数。由于我没有无理数的例子(即使 PI 也被限制在固定位数,因此可以表示为 2 个整数的商,使其成为有理数),我将使用循环小数来说明问题。我改了N*a/Na/N*N因为它用整数更好地说明了问题,但它们是等价的:

a = BigDecimal(1)
N = BigDecimal(3)
a/N = 0.333...
a/N*N = 0.999...

如您在上面的示例中所见,您可以使用任意多的小数位和任何舍入模式,但结果永远不会等于 1。(尽管每次使用不同的舍入模式都可能得到 1操作,即 BigDecimal(3, roundHalfEven) * (BigDecimal(1, roundUp) / 3) )

控制数字比较可以做的一件事是在执行算术运算时使用更高的精度,并在比较时四舍五入到所需的(较低的)精度:

val HighPrecision = new java.math.MathContext(36, java.math.RoundingMode.HALF_EVEN);
val TargetPrecision = java.math.MathContext.DECIMAL128;

val a = BigDecimal(1, HighPrecision)
val N = BigDecimal(3, HighPrecision)
(a/N*N).round(TargetPrecision) == a.round(TargetPrecision)

在上面的示例中,最后一个表达式的计算结果为 true .

更新

要回答您的评论,虽然 BigDecimal 是任意精度,但它仍然受到精度的限制。它可以是 34 也可以是 1000000(如果你有足够的内存)。 BigDecimal 不知道 1 / 30.33<repeating> .如果您考虑除法是如何工作的,那么 BigDecimal 无法确定它在重复而不执行除法到无限小数位。但由于精度为 2 表示它可以在 2 位小数后停止除法,它只知道 1 / 30.33 .

关于java - Scala 中的 BigDecimal,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19691151/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com