KLordy
KLordy

Reputation: 15

How to achieve function exp on BigDecimal in scala?

I wanna to call exp on BigDecimal,while it seems that BigDecimal does not support this function directly.How can I achieve this goal?

Upvotes: 0

Views: 340

Answers (2)

Dima
Dima

Reputation: 40510

Something like this maybe:

 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

It sums up the first p members of the Taylor series for e^x. Taylor series converges pretty quickly, so this should give you a fairly good precision even with relatively small p values. etox(1, 20) for example, gets 18 digits right (in about 100 microseconds), which is already better, than Math.E (new BigDecimal(Math.E).pow(1) takes ~70 micros).

You can control the precision vs. speed by adjusting the p. On my laptop etox(1938435340345L, 1000) takes about 50 milliseconds, while etox(1938435340345L, 10000) took 17.5 seconds.

Note, that the higher values of x are, the greater p you need to get an adequate precision. For x=1 for example, p=20 is enough, as I mentioned earlier, but if x=25, then you need p to be at least 100 to beat the .pow precision.

I am wondering, why this is not linear. Must have to do with the work involved to calculate those huge factorials, and gc'ing memory it takes to represent them ...

As a compromise for higher x values, you can do something like: etox(1, 100).pow(25). This gives you better precision than etox(25, 100), in about the same time. BigDecimal(Math.E).pow(100) takes 64 microseconds, and computes the first 14 digits accurately. etox(1, 1000).pow(100) takes 1.4 milliseconds, and is accurate to the 33rd digit.

Update actually, etox(100, 1000) gets 34 digits correctly in 1.1 millis ... so, I guess, it doesn't matter all that much which form to use. I would expect the difference to be more significant for larger x though. For example etox(1000, 1000) is way off, while etox(1, 1000).pow(1000) is still pretty good.

Upvotes: 0

kliew
kliew

Reputation: 3183

math.exp(myDecimal.toDouble) with some loss of precision due to double encoding.

Upvotes: 1

Related Questions