¿Cuál es la forma más rápida de obtener el valor de π?

Estoy buscando la manera más rápida de obtener el valor de π, como un desafío personal. Más específicamente, estoy usando formas que no involucran usar#define constantes comoM_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 una línea de base para comparar con las otras versiones. En mis pruebas, con incorporaciones, las4 * atan(1) La versión es la más rápida en GCC 4.2, porque se pliega automáticamenteatan(1) en una constante. Con-fno-builtin especificado, elatan2(0, -1) La versión es la más rápida.

Aquí está el programa principal de pruebas (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 montaje 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 construye 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 varias marcas de compilación (también he comparado 32 bits con 64 bits, porque las optimizaciones son diferentes), también he intentado cambiar el orden de las pruebas. Pero aún así, laatan2(0, -1) La versión todavía sale en la parte superior cada vez.

Respuestas a la pregunta(23)

Su respuesta a la pregunta