The pow Function

Behind the Scenes of a Library Function

Students that are new to programming often make poor decisions when it comes to choosing a particular technique to use. For the most part, this is unavoidable, as they do not have the necessary experience when they are first starting out. As the students gain more experience with programming, either in lectures or actual hands-on programming, they begin to understand why one technique is preferable to another.

A classic example of this is when new students need to square a number (e.g. x2). Instinctively, they look for the "exponent" or "power" operator and when they realize that there isn't one, they look for a function to do the job. Incidentally, some languages do have an exponent operator. BASIC uses the caret: ^ and FORTRAN and Python both use two asterisks: **

However, for integer exponents, it is always better to simply do the multiplication rather than call the (very expensive) pow function. Let's look at a simple example.

Using the pow functionUsing simple multiplication
#include <stdio.h> /* printf */
#include <math.h>  /* pow    */

int main(void)
{
  int i;
  int count = 20000000;
  double foo = 0.0;
  int print;

  scanf("%i", &print);

  for (i = 0; i < count; i++)
    foo += pow(i, 2);

  if (print)
    printf("%f", foo);
  
  return 0;
}
#include <stdio.h> /* printf */


int main(void)
{
  int i;
  int count = 20000000;
  double foo = 0.0;
  int print;

  scanf("%i", &print);

  for (i = 0; i < count; i++)
    foo += i * i;

  if (print)
    printf("%f", foo);
  
  return 0;
}
The reason for the print variable is to prevent the compilers from "optimizing away" the code (since foo isn't going to be used anywhere).

The first program above uses the pow function and the second one simply multiplies the number by itself, which is exactly what squaring a number does. Both programs perform their operation 20,000,000 times. We can time these programs to see if there is any difference. The results are very interesting.

These timings were done with
this function call: pow(i, 2)
These timings were done with
this function call: pow(i, 2.1)
GNU gcc 7.2.0:
Optimizationpow(i, 2)i * i
-O0
-O1
-O2
-O3
2.036
0.477
0.165
0.163
0.487
0.483
0.165
0.163
Microsoft 19.0 (VS 2014):
Optimizationpow(i, 2)i * i
-Od
-O2
-Ox
9.55
8.32
8.35
0.53
0.28
0.27
GNU gcc 7.2.0:
Optimizationpow(i, 2.1)i * i
-O0
-O1
-O2
-O3
11.003
10.823
10.670
10.747
----
----
----
----
Microsoft 19.0 (VS 2014):
Optimizationpow(i, 2.1)i * i
-Od
-O2
-Ox
9.98
8.31
8.42
----
----
----

To really understand exactly what's going on in the pow function, you have to look at the source code. The pow(x, y) function is in w_pow.c, which, in turn, calls another function, __ieee754_pow(x,y), in e_pow.c. (This code is from the GNU gcc libraries). Look at that code and you'll see why the function is so much slower than simply doing i * i. Also, you'll see this near the beginning of the function:

if (y == 1.0) return x;
if (y == 2.0) return x*x;     <---- significant optimization!!!
if (y == -1.0) return 1.0/x;
if (y == 0) return 1.0;
That explains why there is little time difference between calling the pow function with an exponent of 2 and simply multiplying the two numbers together. I haven't looked at the source code for the other compilers, but I would guess that those libraries are not optimizing like the GNU library does.

w_pow.c
e_pow.c

Options That Control Optimization for the gcc compiler. This is an advanced document that explains all of the optimizations that the GNU gcc compiler can do to your code.