Estoy buscando la forma más rápida de obtener el valor de π, como un desafío personal. Más específicamente, estoy usando formas que no implican el uso de #define
constantes como M_PI
, o codificar el número en.
El siguiente programa prueba las diversas formas que conozco. La versión de ensamblaje en línea es, en teoría, la opción más rápida, aunque claramente no es portátil. Lo he incluido como referencia para compararlo con las otras versiones. En mis pruebas, con funciones integradas, la 4 * atan(1)
versión es más rápida en GCC 4.2, porque se pliega automáticamente atan(1)
en una constante. Con -fno-builtin
especificado, la atan2(0, -1)
versión es más rápida.
Aquí está el programa de prueba 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;
}
Y el material de ensamblaje en línea ( fldpi.c
) que solo funcionará para sistemas x86 y x64:
double
fldpi()
{
double pi;
asm("fldpi" : "=t" (pi));
return pi;
}
Y un script de compilación que compila todas las configuraciones que estoy probando ( 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
Además de probar entre varios indicadores del compilador (también he comparado 32 bits contra 64 bits porque las optimizaciones son diferentes), también he intentado cambiar el orden de las pruebas. Pero aún así, la atan2(0, -1)
versión sigue apareciendo en todo momento.