Saya mencari cara tercepat untuk mendapatkan nilai π, sebagai tantangan pribadi. Lebih khusus lagi, saya menggunakan cara-cara yang tidak melibatkan penggunaan #define
konstanta seperti M_PI
, atau hard-coding nomor.
Program di bawah ini menguji berbagai cara yang saya ketahui. Versi perakitan inline, secara teori, adalah pilihan tercepat, meskipun jelas tidak portabel. Saya memasukkannya sebagai data dasar untuk dibandingkan dengan versi lainnya. Dalam pengujian saya, dengan built-in, 4 * atan(1)
versi ini tercepat di GCC 4.2, karena otomatis melipat atan(1)
menjadi konstanta. Dengan -fno-builtin
ditentukan, atan2(0, -1)
versi ini tercepat.
Inilah program pengujian utama ( pitimes.c
):
#include <math.h>
#include <stdio.h>
#include <time.h>
#define ITERS 10000000
#define TESTWITH(x) { \
diff = 0.0; \
time1 = clock(); \
for (i = 0; i < ITERS; ++i) \
diff += (x) - M_PI; \
time2 = clock(); \
printf("%s\t=> %e, time => %f\n", #x, diff, diffclock(time2, time1)); \
}
static inline double
diffclock(clock_t time1, clock_t time0)
{
return (double) (time1 - time0) / CLOCKS_PER_SEC;
}
int
main()
{
int i;
clock_t time1, time2;
double diff;
/* Warmup. The atan2 case catches GCC's atan folding (which would
* optimise the ``4 * atan(1) - M_PI'' to a no-op), if -fno-builtin
* is not used. */
TESTWITH(4 * atan(1))
TESTWITH(4 * atan2(1, 1))
#if defined(__GNUC__) && (defined(__i386__) || defined(__amd64__))
extern double fldpi();
TESTWITH(fldpi())
#endif
/* Actual tests start here. */
TESTWITH(atan2(0, -1))
TESTWITH(acos(-1))
TESTWITH(2 * asin(1))
TESTWITH(4 * atan2(1, 1))
TESTWITH(4 * atan(1))
return 0;
}
Dan hal-hal perakitan inline ( fldpi.c
) yang hanya akan bekerja untuk sistem x86 dan x64:
double
fldpi()
{
double pi;
asm("fldpi" : "=t" (pi));
return pi;
}
Dan skrip build yang membangun semua konfigurasi yang saya uji ( build.sh
):
#!/bin/sh
gcc -O3 -Wall -c -m32 -o fldpi-32.o fldpi.c
gcc -O3 -Wall -c -m64 -o fldpi-64.o fldpi.c
gcc -O3 -Wall -ffast-math -m32 -o pitimes1-32 pitimes.c fldpi-32.o
gcc -O3 -Wall -m32 -o pitimes2-32 pitimes.c fldpi-32.o -lm
gcc -O3 -Wall -fno-builtin -m32 -o pitimes3-32 pitimes.c fldpi-32.o -lm
gcc -O3 -Wall -ffast-math -m64 -o pitimes1-64 pitimes.c fldpi-64.o -lm
gcc -O3 -Wall -m64 -o pitimes2-64 pitimes.c fldpi-64.o -lm
gcc -O3 -Wall -fno-builtin -m64 -o pitimes3-64 pitimes.c fldpi-64.o -lm
Terlepas dari pengujian antara berbagai flag compiler (saya telah membandingkan 32-bit dengan 64-bit juga karena pengoptimalannya berbeda), saya juga telah mencoba mengganti urutan pengujian. Tapi tetap saja, atan2(0, -1)
versi ini masih keluar setiap saat.