BigDecimal精确爆炸

时间:2012-12-31 03:30:56

标签: java scala math bigdecimal arbitrary-precision

我正在尝试以大于双精度的固定精度在Scala(和/或Java)中进行计算。我正在使用带有Scala默认MathContext的BigDecimals,它具有精度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。*之间的change in the handling of MathContexts造成的。 (感谢Paul Phillips指出提交。)另见this discussion

3 个答案:

答案 0 :(得分: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).precision正如您预期的那样34

答案 1 :(得分:0)

实际上,我相信最后一行

(1 + z40*z40).precision

生成结果34(不是81)。我不认为这里的精确度实际上在增加。

答案 2 :(得分: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