SORU
1 AĞUSTOS 2008, Cuma


Π değerini almak için en hızlı yolu nedir?

Çözümler her dilde hoş geldiniz. :-) Kişisel bir meydan okuma olarak π değeri, elde etmek için en hızlı yol arıyorum. Daha spesifik olarak M_PI, #defined sabitleri kullanarak veya sabit kodlama sayısında karıştırmayın bu yolu kullanıyorum.

Aşağıdaki program biliyorum çeşitli şekillerde sınar. Satır içi derleme sürümü açıkça taşınabilir olmasa da, teorik olarak, en hızlı seçenektir; karşı diğer sürümleri karşılaştırmak için bir temel olarak ekledim. Built-ins ile benim testlerde,, 4 * atan(1) sürümü otomatik kıvrımlar atan(1) sürekli içine çünkü 4.2, GCC hızlı. -fno-builtin belirtilen atan2(0, -1) sürüm hızlı.

Burada ana test programı (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;
}

Ve satır içi derleme şeyler (fldpi.c), yalnızca x 86 ve x 64 sistemleri için çalışacağını kaydetti:

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

Ve bir test ediyorum tüm yapılandırmaları (build.sh) oluşturur komut dosyası oluşturmak:

#!/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

Çeşitli derleyici bayrakları arasında testler dışında (64-bit karşı 32-bit optimizasyon farklı olduğu için de, karşılaştırıldığında oldum), ayrıca etrafında testlerin Sırasını Değiştirme, denedim. atan2(0, -1) sürümü hala top her zaman, ama çıkıyor.

CEVAP
2 AĞUSTOS 2008, CUMARTESİ


Belirtildiği gibi Monte Carlo method, bazı büyük kavramlar geçerlidir ama görülüyor ki, en makul kullanışlılık olarak zor bir iş değil, değil değil. Ayrıca, bu tüm sizin için ne arıyorsanız bağlıdır. Benim bildiğim en hızlı pi rakamını sabit kodlanmıştır. Pi Pi[PDF], orada bakıyor formüllerin bir çoğu.

Burada hızlı bir şekilde yakınsak bir yöntem (yineleme başına~14digits). Mevcut en hızlı uygulama, PiFast, FFT ile bu formülü kullanır. Eğer kuralları bellidir beri formül yazacağım. Bu formül neredeyse Ramanujan and discovered by Chudnovsky tarafından bulundu. Numarasını bir yöntem değildir bu yüzden birkaç milyar rakamını göz ardı etmek hesapladı, nasıl aslında. Formülü hızlı bir şekilde faktöriyel bölme olduğumuz için, o zaman böyle bir hüküm çıkarmak için hesaplama gecikme için avantajlı olurdu dolup taşacaktır.

enter image description here

enter image description here

nerede

enter image description here

Aşağıda Brent–Salamin algorithm. Wikipedia a ve b 'yeterli' (a b)^2/4t pi. bir yaklaşım olacak yakın zaman bahseder Emin değilim ne kadar yakın' anlamına gelir, ama benim testler, bir yineleme var 2digits, iki tane 7, üç tane vardı 15, tabii bunun iki katına, yani olabilir hata dayandığı temsili ve 'gerçek' hesaplama daha doğru olabilir.

let pi_2 iters =
    let rec loop_ a b t p i =
        if i = 0 then a,b,t,p
        else
            let a_n = (a  . b) /. 2.0 
            and b_n = sqrt (a*.b)
            and p_n = 2.0 *. p in
            let t_n = t -. (p *. (a -. a_n) *. (a -. a_n)) in
            loop_ a_n b_n t_n p_n (i - 1)
    in 
    let a,b,t,p = loop_ (1.0) (1.0 /. (sqrt 2.0)) (1.0/.4.0) (1.0) iters in
    (a  . b) *. (a  . b) /. (4.0 *. t)

Son olarak, biraz pi golf (800 basamaklı) hakkında? 160 karakter!

int a=10000,b,c=2800,d,e,f[2801],g;main(){for(;b-c;)f[b  ]=a/5;for(;d=0,g=c*2;c-=14,printf("%.4d",e d/a),e=d%a)for(b=c;d =f[b]*a,f[b]=d%--g,d/=g--,--b;d*=b);}

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • EEVblog

    EEVblog

    4 NİSAN 2009
  • Eric Magidson

    Eric Magidso

    4 Ocak 2009
  • MisterBrightside

    MisterBright

    24 Mart 2006