Je cherche le moyen le plus rapide pour obtenir la valeur de π, comme défi personnel. Plus précisément, j'utilise des méthodes qui n'impliquent pas l'utilisation de #define
constantes comme M_PI
ou le codage en dur du nombre.
Le programme ci-dessous teste les différentes manières que je connais. La version d'assemblage en ligne est, en théorie, l'option la plus rapide, bien qu'elle ne soit clairement pas portable. Je l'ai inclus comme référence pour comparer avec les autres versions. Dans mes tests, avec les intégrés, la 4 * atan(1)
version est la plus rapide sur GCC 4.2, car elle se replie automatiquement atan(1)
en une constante. Avec -fno-builtin
spécifié, la atan2(0, -1)
version est la plus rapide.
Voici le programme de test principal ( 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;
}
Et les éléments d'assemblage en ligne ( fldpi.c
) qui ne fonctionneront que pour les systèmes x86 et x64:
double
fldpi()
{
double pi;
asm("fldpi" : "=t" (pi));
return pi;
}
Et un script de construction qui construit toutes les configurations que je 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
En plus de tester entre différents drapeaux du compilateur (j'ai comparé 32 bits contre 64 bits aussi parce que les optimisations sont différentes), j'ai également essayé de changer l'ordre des tests. Mais toujours, la atan2(0, -1)
version sort toujours en tête à chaque fois.