首页 文章

BigDecimal精确爆炸

提问于
浏览
5

我使用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相比可以忽略不计) . 我怎么能得到这种算术?

Update: 此行为是由于Scala 2.9 . *和2.10 . *之间的change in the handling of MathContexts . (感谢Paul Phillips指出了提交 . )另见this discussion .

3 回答

  • 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 .

  • 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 如您所料 .

  • 0

    实际上,我相信最后一行

    (1 + z40*z40).precision
    

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

相关问题