0

I have just been doing some benchmarks with std::pow for doubles. For the case that the exponent is an integer value (although coded as a double) (std::pow(a, 2.0), std::pow(a, 3.0)... I found that std::pow is much slower than just doing the multiplications when compiling with -O3

std::pow(a, 2.0) // a*a
std::pow(a, 3.0) // a*a*a
std::pow(a, 4.0) // a*a*a*a
...

except for the case of 2.0, which behaves exactly the same and produces the same binary code when compiling with -O3.

Why is the compiler optimizing the 2.0 case but not being able to compile the 3.0 case as aaa?

When compiling with -O3 -ffast-math I get exactly the same binary code for 2.0 and 3.0 (havent tested above). How is this?

Edit: this question has been marked as duplicate, which I dont agrede. First of all, this is about c++, and the related question is about c. I am not asking why pow(a, 3.0) is slower than aaa, but about the differences between pow and multiplications and why in power of 2 they produce exactly the same code, but not for other exponents.

jjcasmar
  • 1,387
  • 1
  • 18
  • 30
  • 9
    You'll need to open up your compilers implementation and look at the code. My instincts say there is a special case in the function where if the exponent is 2, it just return `a*a`, but if it is not then it falls back to using complicated math to approximate the value. FWIW, you should not use `pow` for integer powers because it does convert to a floating point value which can lead to off by one errors due to floating point errors – NathanOliver May 17 '22 at 21:48
  • 1
    Even with floating point, `pow(..., 2.0)` is mostly a nothing-burger. It should translate to simply incrementing the exponent part of the binary value, leaving the mantissa alone. – Sam Varshavchik May 17 '22 at 21:54
  • @Sam you seem to be confusing pow with a different function. – Marc Glisse May 17 '22 at 23:02
  • While mathematically equivalent (for positive a), `a*a*a` and pow(a,3) could round differently, so the compiler will only consider them equivalent if you tell it that you don't care about the difference (`-ffast-math` for instance). – Marc Glisse May 17 '22 at 23:04
  • You'd have to look at your compiler's internals and (if available) design documentation. There's no mandate for implementations to do *any* optimisation of `pow()` for particular inputs. Optimisation or lack there-of is a QoI (quality of implementation) and, with QoI concerns, vendors compete by doing things differently to suit different end users. Personally, for fixed integer exponents, I'd write a set of multiplications rather than using `pow()` and, for integral bases, I'd usually avoid using floating point operations or functions at all - that's part of my QoI approach for my code. – Peter May 18 '22 at 00:14
  • On which compiler...? – Aykhan Hagverdili May 18 '22 at 00:41
  • @AyxanHaqverdili Clang12 and gcc 10.3 – jjcasmar May 18 '22 at 05:35
  • @MarcGlisse I though the same thing, but in practice I failed to find any counter example that `std::pow` gives different result compared to `a*a*a` (tested for a wide range of values). In fact, the same thing appears to be true for `a*a*a*a` though I only tested this case with few values). However, it make sense for bigger integer exponents as the libmath can be linked dynamically and can be different from the one delivered with the compiler. The compiler is not aware of what the linker will do (dependent of user flag and even the runtime environment if dynamically linked). – Jérôme Richard May 18 '22 at 18:53

0 Answers0