Ich suche nach dem schnellsten Weg, um den Wert von π als persönliche Herausforderung zu erhalten. Insbesondere verwende ich Methoden, bei denen keine #define
Konstanten wie M_PI
oder die Codierung der Zahl in verwendet werden.
Das folgende Programm testet die verschiedenen mir bekannten Möglichkeiten. Die Inline-Assembly-Version ist theoretisch die schnellste Option, obwohl sie eindeutig nicht portierbar ist. Ich habe es als Basis für den Vergleich mit den anderen Versionen aufgenommen. In meinen Tests mit integrierten Funktionen ist die 4 * atan(1)
Version unter GCC 4.2 am schnellsten, da sie die automatisch atan(1)
in eine Konstante faltet . Mit -fno-builtin
angegeben ist die atan2(0, -1)
Version am schnellsten.
Hier ist das Haupttestprogramm ( 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;
}
Und das Inline-Assembly-Material ( fldpi.c
), das nur für x86- und x64-Systeme funktioniert:
double
fldpi()
{
double pi;
asm("fldpi" : "=t" (pi));
return pi;
}
Und ein Build-Skript, das alle Konfigurationen erstellt, die ich teste ( 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
Abgesehen von Tests zwischen verschiedenen Compiler-Flags (ich habe auch 32-Bit mit 64-Bit verglichen, weil die Optimierungen unterschiedlich sind), habe ich auch versucht, die Reihenfolge der Tests zu ändern. Trotzdem hat die atan2(0, -1)
Version jedes Mal die Nase vorn.