如何在scala中实现BigDecimal上的函数exp?

时间:2016-03-25 04:33:43

标签: scala

我想在BigDecimal上调用exp,而BigDecimal似乎不直接支持这个函数。我怎样才能实现这个目标?

2 个答案:

答案 0 :(得分:1)

math.exp(myDecimal.toDouble) 由于双重编码而导致精度下降。

答案 1 :(得分:0)

这样的事情可能是:

 def etox(x: BigDecimal, p: Int) = 
  Stream.from(1).takeWhile(_ <= p)
    .foldLeft((BigDecimal(1), BigDecimal(1)) -> BigDecimal(1)) {
      case (((fac, pow), res), n) => 
        val f = fac * n
        val p = pow * x
       ((f, p), res + p/f)
    }._2

它总结了泰勒系列的第一个p成员e ^ x。泰勒级数很快收敛,所以即使值p相对较小,这也应该给你一个相当好的精度。例如,etox(1, 20)得到18位数(大约100微秒),这已经比Math.Enew BigDecimal(Math.E).pow(1)需要大约70微秒)好了。

您可以通过调整p来控制精度与速度。 在我的笔记本电脑上etox(1938435340345L, 1000)需要大约50毫秒,而etox(1938435340345L, 10000)需要17.5秒。

请注意,x的值越高,获得足够精度所需的p越大。例如,对于x=1p=20就足够了,正如我之前提到的那样,但如果x=25,那么您需要p至少100才能击败.pow精度。

我想知道,为什么这不是线性的。必须与所涉及的工作有关,以计算那些巨大的阶乘,以及代表它们的gc记忆...

作为较高x值的折衷方案,您可以执行以下操作: etox(1, 100).pow(25)。这使您在大约相同的时间内比etox(25, 100)更精确。 BigDecimal(Math.E).pow(100)需要64微秒,并准确计算前14位数。 etox(1, 1000).pow(100)需要1.4毫秒,并且精确到第33位。

更新实际上,etox(100, 1000)在1.1毫米内正确获得34位数...所以,我想,使用哪种形式并不重要。我希望差异对于较大的x来说更重要。 例如etox(1000, 1000)离开了,而etox(1, 1000).pow(1000)仍然相当不错。