5

我正在尝试以大于双精度的固定精度在 Scala(和/或 Java)中进行计算。我将 BigDecimals 与 Scala 的默认MathContext一起使用,其精度为 34。即使所有输入都具有此精度,但我发现经过几次计算后,结果的精度开始爆炸式增长。

这是一个我认为可以说明问题的示例计算:

import math.BigDecimal

val z40 = BigDecimal(0).setScale(40) // 0E-40
z40.scale                            // 40
z40.precision                        // 1
(1 + z40*z40).precision              // 81

结果为 81,精度高于z40. 就我而言,我从不使用 setScale,但在计算中会出现比例非常大的零。

这不是我想要的行为。我想要(1 + z40*z40)精度 34 - 执行计算的 MathContext 的精度(因为z40*z40与 1 相比小得可以忽略不计)。我怎样才能得到这种算术?

更新:此行为是由于Scala 2.9.* 和 2.10.* 之间的 MathContexts 处理发生了变化。(感谢 Paul Phillips 指出提交。)另请参阅此讨论

4

3 回答 3

3

似乎很奇怪。我尝试了您的代码并得到了您预期的结果:

$ scala
Welcome to Scala version 2.9.2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_10).
Type in expressions to have them evaluated.
Type :help for more information.

scala> import math.BigDecimal
import math.BigDecimal

scala> val z40 = BigDecimal(0).setScale(40)
z40: scala.math.BigDecimal = 0E-40

scala> z40.scale
res0: Int = 40

scala> z40.precision
res1: Int = 1

scala> (1 + z40*z40).precision
res2: Int = 34

scala> _

如您所见,正如您(1+z40*z40).precision34料。

于 2012-12-31T04:12:09.440 回答
0

其实我相信最后一行

(1 + z40*z40).precision

产生结果34(不是81)。我认为这里的精度实际上并没有增加。

于 2012-12-31T04:10:52.883 回答
0

以下是如何创建 BigDecimals:

val z1 = BigDecimal(1, new java.math.MathContext(
  40, java.math.RoundingMode.valueOf(
    scala.math.BigDecimal.RoundingMode.HALF_UP.toString)))

val z40 = BigDecimal(0, new java.math.MathContext(
  40, java.math.RoundingMode.valueOf(
    scala.math.BigDecimal.RoundingMode.HALF_UP.toString)))

看不到任何精准爆炸。只需使用适当的MathContext.

于 2012-12-31T09:21:45.693 回答