Lambdageek correctly points out that because associativity does not hold for floating-point numbers, the "optimization" of a*a*a*a*a*a
to (a*a*a)*(a*a*a)
may change the value. This is why it is disallowed by C99 (unless specifically allowed by the user, via compiler flag or pragma). Generally, the assumption is that the programmer wrote what she did for a reason, and the compiler should respect that. If you want (a*a*a)*(a*a*a)
, write that.
That can be a pain to write, though; why can't the compiler just do [what you consider to be] the right thing when you use pow(a,6)
? Because it would be the wrong thing to do. On a platform with a good math library, pow(a,6)
is significantly more accurate than either a*a*a*a*a*a
or (a*a*a)*(a*a*a)
. Just to provide some data, I ran a small experiment on my Mac Pro, measuring the worst error in evaluating a^6 for all single-precision floating numbers between [1,2):
worst relative error using powf(a, 6.f): 5.96e-08
worst relative error using (a*a*a)*(a*a*a): 2.94e-07
worst relative error using a*a*a*a*a*a: 2.58e-07
Using pow
instead of a multiplication tree reduces the error bound by a factor of 4. Compilers should not (and generally do not) make "optimizations" that increase error unless licensed to do so by the user (e.g. via -ffast-math
).
Note that GCC provides __builtin_powi(x,n)
as an alternative to pow( )
, which should generate an inline multiplication tree. Use that if you want to trade off accuracy for performance, but do not want to enable fast-math.