stripe / rainier

Bayesian inference in Scala.
https://rainier.fit
Apache License 2.0
432 stars 51 forks source link

Move away from BigDecimal #412

Closed avibryant closed 4 years ago

avibryant commented 4 years ago

BigDecimal causes performance problems, especially in the forward simulation phase. We may be able to get clever about a mixture of Double and Int representations that gives us the best of both worlds.

avibryant commented 4 years ago

cc @sritchie

The motivation for using BigDecimal is to ensure that constants which simplify to small integers mathematically, and which end up as coefficients or exponents, will also simplify to small integers numerically.

A contrived example might be:

(x + 0.1)(2x + 0.1) - (3x/10)
= 3x^2 + 0.2x + 0.1x +0.01 - 0.3x
= 3x^2 + 0.01

However, with floating point math, you end up with a (5.55e-17 x) term in there you don't want.

avibryant commented 4 years ago

I bet it would be good enough to implement a simple case class Fraction(numerator: Int, denominator: Int), and two different constant Real types, one with double and one with fraction, and then stay in fraction-space as long as possible but convert to double whenever necessary.

avibryant commented 4 years ago

A weird idea that would be interesting to play with is: what about a single representation which is (numerator: Double, denominator: Int)? The intuition here is just that the problems tend to come from adjusting the order of magnitude down and then up again (eg dividing by 10 and then later multiplying by 10), and so if we can isolate the double values somewhat from these shifts, we should avoid a lot of the problems.