関数の速度(2)

前回、


double x = 0.5;
for(int i = 0; i < N; i++) {
sum += exp(x);
x += dx; // dx = 1e-8
}

とした、すなわち、
exp(0.5) + exp(0.50000001) + exp(0.50000002) + ...
を計算しているのは、確実にexpをN回計算するため。
これを、


double x = 0.5;
for(int i = 0; i < N; i++) {
sum += exp(x);
}

とする、すなわち、
exp(0.5) + exp(0.5) + exp(0.5) + ...
を計算すると、コンパイラオプションによってはexp(0.5)を1回しか計算しないこともある。
当たり前だが、念のため。


加法定理があると速くなる。
例えば、cosなら、


double sum = 0;
double x = 0.5;
double cos2 = cos(x);
double sin2 = sin(x);
double cos_dx = cos(dx);
double sin_dx = sin(dx);
x += dx;
for(int i = 1; i < N; i++) {
double cos_tmp = cos2;
cos2 = cos_tmp * cos_dx - sin2 * sin_dx;
sin2 = sin2 * cos_dx + cos_tmp * sin_dx;
sum += cos2;
x += dx;
}

これで、45nsが4.3nsとなった。
expだと等比数列という話もある。
等比数列はあまりないかもしれないが、
こういう高速化も本当に必要ならやらねばならない。
さすがにここまではコンパイラはやらないだろう。