Szukam najszybszego sposobu na uzyskanie wartości π jako osobistego wyzwania. Mówiąc dokładniej, korzystam ze sposobów, które nie wymagają użycia #define
stałych, takich jak M_PI
lub zakodowania na stałe liczby.
Poniższy program testuje różne znane mi sposoby. Wersja zestawu wbudowanego jest teoretycznie najszybszą opcją, choć oczywiście nie jest przenośna. Podałem go jako punkt odniesienia do porównania z innymi wersjami. W moich testach, z wbudowanymi 4 * atan(1)
wersjami , wersja jest najszybsza na GCC 4.2, ponieważ automatycznie składa się atan(1)
w stałą. Z -fno-builtin
określony, atan2(0, -1)
wersja jest najszybszy.
Oto główny program testujący ( 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;
}
A wbudowane elementy asemblera ( fldpi.c
), które będą działać tylko w systemach x86 i x64:
double
fldpi()
{
double pi;
asm("fldpi" : "=t" (pi));
return pi;
}
I skrypt kompilacji, który buduje wszystkie konfiguracje, które testuję ( 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
Oprócz testowania różnych flag kompilatora (porównałem również 32-bitowy z 64-bitowym, ponieważ różne są optymalizacje), próbowałem również zmienić kolejność testów. Mimo to atan2(0, -1)
wersja wciąż wychodzi na wierzch za każdym razem.