Jaki jest najszybszy sposób uzyskania wartości π?

Szukam najszybszego sposobu na uzyskanie wartości π, jako osobistego wyzwania. Dokładniej, używam sposobów, które nie wymagają używania#define stałe takie jakM_PIlub kodowanie na stałe numeru.

Poniższy program sprawdza różne sposoby, które znam. Wersja montażowa inline jest teoretycznie najszybszą opcją, choć najwyraźniej nie jest przenośna. Włączyłem go jako linię bazową do porównania z innymi wersjami. W moich testach z wbudowanymi4 * atan(1) wersja jest najszybsza w GCC 4.2, ponieważ automatycznie składaatan(1) w stałą. Z-fno-builtin określony,atan2(0, -1) wersja jest najszybsza.

Oto główny program testujący (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;
}

I rzeczy do montażu inline (fldpi.c), które będą działać tylko w systemach x86 i x64:

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

I skrypt kompilacji, który buduje wszystkie konfiguracje, które testuję (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

Oprócz testowania między różnymi flagami kompilatora (porównałem też 32-bitowe z 64-bitowymi, ponieważ optymalizacje są różne), próbowałem również zmienić kolejność testów wokół. Ale wciążatan2(0, -1) wersja zawsze wychodzi na wierzch za każdym razem.

questionAnswers(23)

yourAnswerToTheQuestion