Quel est le moyen le plus rapide d'obtenir la valeur de π ?

Je cherche le moyen le plus rapide d'obtenir la valeur de π, en tant que défi personnel. Plus précisément, j'utilise des méthodes qui n'impliquent pas l'utilisation de constantes #define comme M_PI, ou le codage en dur du nombre.

Le programme ci-dessous teste les différentes méthodes 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 version 4 * atan(1) est la plus rapide sur GCC 4.2, car elle replie automatiquement le atan(1) en une constante. Avec -fno-builtin spécifié, la version atan2(0, -1) 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	=> %e, time => %f
', #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 l'assemblage en ligne (fldpi.c) qui ne fonctionnera que pour les systèmes x86 et x64 :

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

Et un script de build 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

Outre les tests entre différents indicateurs de compilateur (j'ai également comparé 32 bits à 64 bits, car les optimisations sont différentes), j'ai également essayé de modifier l'ordre des tests. Néanmoins, la version atan2(0, -1) arrive toujours en tête à chaque fois.

请先 登录 后评论