Fast pow()


#1

I’m currently working on a project that uses pow in its DSP maths, and I want to make sure it’s fast. I’ve found dsp::FastMathApproximations, but it doesn’t include pow.

https://docs.juce.com/master/structdsp_1_1FastMathApproximations.html

I’ve also found some fast approximation equations online at https://martin.ankerl.com/2012/01/25/optimized-approximative-pow-in-c-and-cpp/.

The equations are

// 4.2 times as fast as normal pow
inline double fastPow(double a, double b) {
  union {
    double d;
    int x[2];
  } u = { a };
  u.x[1] = (int)(b * (u.x[1] - 1072632447) + 1072632447);
  u.x[0] = 0;
  return u.d;
}

~and~

// 3.3 times as fast as normal pow
// should be much more precise with large b
inline double fastPrecisePow(double a, double b) {
  // calculate approximation with fraction of the exponent
  int e = (int) b;
  union {
    double d;
    int x[2];
  } u = { a };
  u.x[1] = (int)((b - e) * (u.x[1] - 1072632447) + 1072632447);
  u.x[0] = 0;

  // exponentiation by squaring with the exponent's integer part
  // double r = u.d makes everything much slower, not sure why
  double r = 1.0;
  while (e) {
    if (e & 1) {
      r *= a;
    }
    a *= a;
    e >>= 1;
  }

  return r * u.d;
}

Does anyone here have any experience with fast pow? What are your thoughts?


#2


#3

Well, there’s exp(): https://docs.juce.com/master/structdsp_1_1FastMathApproximations.html#a5b300b4425df20821f40d05669deea4b


#4

I’l not sure what exp() is, but given it only takes one argument, I think it might be something else.


#5

exp(x) = e^x and by adjusting x you can calculate y^z with help of exp(). So depending on your desired base or exponent, that might be useful :slight_smile:


#6

Oh, neat! Unfortunately my range of values is from 0.001 to 1000, so I don’t think the -6 to +4 would be very happy about that. But I’m going to keep this in my back pocket.

I suppose you also just gave me an answer, which is that it’s probably not very likely to be using such a wide range of values.


#7

To elaborate: pow(x, y) = exp(ln(x) * y)
Edit: to elaborate a little more: in case your base x is constant, you can calculate ´ln(x)´ once and just scale your exponent y with it and calculate the result using the exp approximation.


#8

I’m using fmath for exp and log, it’s a little bit less precise than std, but close enough to svml everywhere AFAIK. Last time I used these to replace pow, I gain a factor of 7 between them.


#9

I don’t know what svml is, but if it works for you, it’ll probably work for me.


#10

Small Vector Math Library, it’s one of Intel’s fast math libraries (lesser known than MKL).