Qual é o caminho mais rápido para obter o valor de π?

Eu estou procurando o caminho mais rápido para obter o valor de π, como um desafio pessoal. Mais especificamente, estou usando maneiras que não envolvem o uso#define constantes comoM_PIou codificando o número em.

O programa abaixo testa as várias maneiras que conheço. A versão de montagem inline é, em teoria, a opção mais rápida, embora claramente não seja portátil. Eu incluí-lo como uma linha de base para comparar com as outras versões. Nos meus testes, com built-ins, o4 * atan(1) A versão é mais rápida no GCC 4.2, porque ela dobra automaticamenteatan(1) em uma constante. Com-fno-builtin especificado, oatan2(0, -1) versão é mais rápida.

Aqui está o programa principal de testes (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;
}

E o material de montagem inline (fldpi.c) que funcionará apenas para sistemas x86 e x64:

double
fldpi()
{
    double pi;
    asm("fldpi" : "=t" (pi));
    return pi;
}

E um script de construção que constrói todas as configurações que estou testando (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

Além de testar entre vários sinalizadores de compilador (comparei o de 32 bits com o de 64 bits também, porque as otimizações são diferentes), também tentei alternar a ordem dos testes. Mas ainda assim, oatan2(0, -1) versão ainda sai no topo de cada vez.

questionAnswers(23)

yourAnswerToTheQuestion