関数の速度(13)

VC2005EEの/O2で。

pow

powはべき乗で、pow(a, b)でabを計算する。
おそらく、bがdoubleの場合は、
ab = exp(b * log(a))
としている。
bがintの場合は、例えば8乗なら、
b *= b; b *= b; b *= b;
で3回の積で求まる、
といったアルゴリズムを使う。
bを振ると、


2.7 10.855s
4 0.889s
16 1.648s
64 2.266s
256 3.196s
1024 5.469s
4096 6.258s
16384 7.103s
65536 8.184s
262144 18.534s

よほどbが大きくならない限りintを使ったほうがいい。
bがdoubleのときはかかる時間に大きさによらないと思えるが、
intの場合はlog(b)にほぼ線形である。
しかし、10万あたりから急に時間がかかるようになる。


#include
#include
#include

#pragma comment (lib, "winmm.lib")

using namespace std;

const int N = (int)1e8;
const double dx = 0.1 / N;

void bench_pow_double(double k) {
int t = timeGetTime();

double sum = 0;
double x = 0.95;
for(int i = 0; i < N; i++) {
sum += pow(x, k);
x += dx;
}

fprintf(stdout, "%.3fs\n", (timeGetTime() - t) * 1e-3);
fprintf(stdout, "%e\n", sum);
}

void bench_pow_int(int k) {
int t = timeGetTime();

double sum = 0;
double x = 0.95;
for(int i = 0; i < N; i++) {
sum += pow(x, k);
x += dx;
}

fprintf(stdout, "%.3fs\n", (timeGetTime() - t) * 1e-3);
fprintf(stdout, "%e\n", sum);
}

void main() {
bench_pow_double(2.7);
for(int i = 1; i < 10; i++) {
int k = 1 << (2 * i);
bench_pow_int(k);
}
}