我正在尝试以大于双精度的固定精度在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。
答案 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
。