Jaki jest najszybszy sposób, aby uzyskać wartość Õ?

głosy
275

Szukam najszybszym sposobem uzyskania wartości Õ, jako osobiste wyzwanie. Dokładniej, używam sposobów, które nie wiążą się z wykorzystaniem #definestałych jak M_PI, lub ciężko kodowania liczby w.

Poniżej program testuje różne sposoby wiem. Wersja montaż inline jest teoretycznie najszybsza opcja, choć wyraźnie nie przenośne. Podaję je jako punkt odniesienia do porównywania przed innymi wersjami. W moich testów, z wbudowanym ins The 4 * atan(1)wersja jest najszybszy na GCC 4.2, ponieważ auto-zagina atan(1)się stała. Z -fno-builtinokreślony, atan2(0, -1)wersja jest najszybszy.

Oto główny program kontrolują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 materiał montażowy (inline fldpi.c), który będzie działał tylko dla systemów x86 i x64:

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

I skrypt kompilacji, które buduje wszystkie konfiguracje Jestem testowania ( 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 pomiędzy różnymi flagami kompilatora (mam 32-bitowy porównaniu przeciwko 64-bit też, bo optymalizacje są różne), ja również próbował włączeniu kolejność testów wokół. Ale Nadal, atan2(0, -1)wersja wciąż wychodzi na górze każdej chwili.

Utwórz 01/08/2008 o 06:21
źródło użytkownik
W innych językach...                            


23 odpowiedzi

głosy
72

Oto ogólny opis techniki obliczania PI, że nauczył w liceum.

I tylko podzielić się tym, bo myślę, że jest na tyle prosty, że każdy może go zapamiętać, na czas nieokreślony, a także uczy Cię koncepcję „Monte Carlo” metod - metody statystyczne, które są z przybyciem na odpowiedzi, które nie od razu wydają się być wywnioskować poprzez procesów losowych.

Narysować kwadrat i wpisać ćwiartkę (jedna czwarta półokręgu) wewnątrz kwadratu (kwadrantu o promieniu równym boku kwadratu, tak, że wypełnia tyle kwadratu, jak to możliwe)

Teraz rzucać dart na placu i nagrywać gdzie wyląduje - czyli wybrać losowy punkt w dowolnym miejscu wewnątrz kwadratu. Oczywiście, że wylądował w środku placu, ale jest to w środku półokręgu? Odnotowuje ten fakt.

Powtórz ten proces wielokrotnie - a znajdziesz tam to stosunek liczby punktów wewnątrz półkola w stosunku do ogólnej liczby rzucony, nazywają ten stosunek x.

Ponieważ obszar kwadratu to czasy R R, można wywnioskować, że obszar półkolu jest x razy r czasy R (czyli x razy r do kwadratu). Stąd x razy 4 daje ci pi.

Nie jest to metoda szybka w użyciu. Ale to dobry przykład metody Monte Carlo. A jeśli spojrzeć wokół, może się okazać, że wiele problemów w inny sposób poza swoje umiejętności obliczeniowe mogą być rozwiązane przez takich metod.

Odpowiedział 01/08/2008 o 14:37
źródło użytkownik

głosy
180

Metoda Monte Carlo , jak wspomniano, stosuje się jakieś wielkie koncepcje ale jest to wyraźnie, nie najszybszy, nie przez długie ujęcie, a nie przez każdego rozsądnego środka. Także, to wszystko zależy od tego, jakiego rodzaju dokładność szukasz. Najszybszy π Znam jedną z cyfr ciężko kodowanych. Patrząc na Pi i Pi [PDF] , istnieje wiele wzorów.

Oto metoda, która zbiega się szybko - około 14 cyfr za iteracji. PiFast obecny najszybszym aplikacji, wykorzystuje tę formułę za pomocą FFT . Ja po prostu napisać formułę, ponieważ kod jest proste. Formuła ta została niemal znaleziony przez Ramanujan i odkryta przez Chudnovsky . To jest rzeczywiście, jak on obliczony kilka miliardów cyfr numeru - więc nie jest to metoda lekceważyć. Wzór wyleje się szybko, ponieważ dzielące silnię, korzystne byłoby następnie opóźnić takich obliczeń w celu usunięcia warunki.

wprowadzić opis obrazu tutaj

wprowadzić opis obrazu tutaj

gdzie,

wprowadzić opis obrazu tutaj

Poniżej przedstawiono algorytm Brent-Salamin . Wikipedia wskazuje, że gdy i b są „wystarczająco blisko”, wówczas (a + b) ² / 4T będzie przybliżeniem Õ. Nie jestem pewien, co „wystarczająco blisko” oznacza, ale z moich badań, jedna iteracja dostał 2 cyfry, dwa dostał 7, a trzy miały 15, oczywiście to jest z podwójnej, więc to może być błąd w oparciu o jej reprezentacji i prawdziwe obliczenie może być bardziej dokładne.

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)

Wreszcie, jak o jakimś pi golf (800 znaków)? 160 znaków!

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);}
Odpowiedział 02/08/2008 o 19:22
źródło użytkownik

głosy
17

Jeśli masz na myśli przez najszybszy najszybszy wpisać w kodzie, oto golfscript rozwiązanie:

;''6666,-2%{2+.2/@*\/10.3??2*+}*`1000<~\;
Odpowiedział 06/08/2008 o 23:54
źródło użytkownik

głosy
40

Jest rzeczywiście cała książka poświęcona (między innymi) do szybkich metod obliczania \ pi: „Pi i AGM”, Jonathan i Peter Borwein ( dostępny na Amazon ).

Uczyłem ZWZ i algorytmów powiązanych sporo: to dość ciekawy (choć czasami nietrywialne).

Należy pamiętać, że aby wdrożyć najnowocześniejsze algorytmy do obliczania \ pi, trzeba będzie multiprecision arytmetyczną bibliotekę ( GMP jest bardzo dobrym wyborem, choć minęło już trochę czasu, odkąd ostatni użył go).

Czas złożoności najlepszych algorytmów w O (M (n) log (n)), gdzie M (n) jest czasowo-złożoność do mnożenia dwóch liczb całkowitych n-bitowych (M (N) = O (n log (n) (log (n))), stosując algorytmy oparte na FFT, które są zwykle wymagane podczas obliczania cyfry \ pi, a taki algorytm realizowany w GMP).

Należy pamiętać, że chociaż matematyka za algorytmów nie może być trywialne, same algorytmy są zwykle kilka linii pseudo-kodu, a ich realizacja jest zazwyczaj bardzo proste (jeśli nie zdecydował się napisać własny multiprecision arytmetyki :-)).

Odpowiedział 24/08/2008 o 18:14
źródło użytkownik

głosy
25

Wzór BBP pozwala obliczyć n-cyfry - w podstawie (2 lub 16), - bez konieczności nawet przejmować z wcześniejszych n-1 cyframi pierwszy :)

Odpowiedział 29/08/2008 o 10:22
źródło użytkownik

głosy
96

Bardzo podoba mi się ten program, który jest zbliżony pi patrząc na jego własnym terenie :-)

IOCCC 1988: westley.c

#define _ -F<00||--F-OO--;
int F=00,OO=00;main(){F_OO();printf("%1.3f\n",4.*-F/OO/OO);}F_OO()
{
            _-_-_-_
       _-_-_-_-_-_-_-_-_
    _-_-_-_-_-_-_-_-_-_-_-_
  _-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
  _-_-_-_-_-_-_-_-_-_-_-_-_-_
    _-_-_-_-_-_-_-_-_-_-_-_
        _-_-_-_-_-_-_-_
            _-_-_-_
}
Odpowiedział 02/09/2008 o 14:28
źródło użytkownik

głosy
15

Oblicz PI w czasie kompilacji z D.

(Skopiowane z DSource.org )

/** Calculate pi at compile time
 *
 * Compile with dmd -c pi.d
 */
module calcpi;

import meta.math;
import meta.conv;

/** real evaluateSeries!(real x, real metafunction!(real y, int n) term)
 *
 * Evaluate a power series at compile time.
 *
 * Given a metafunction of the form
 *  real term!(real y, int n),
 * which gives the nth term of a convergent series at the point y
 * (where the first term is n==1), and a real number x,
 * this metafunction calculates the infinite sum at the point x
 * by adding terms until the sum doesn't change any more.
 */
template evaluateSeries(real x, alias term, int n=1, real sumsofar=0.0)
{
  static if (n>1 && sumsofar == sumsofar + term!(x, n+1)) {
     const real evaluateSeries = sumsofar;
  } else {
     const real evaluateSeries = evaluateSeries!(x, term, n+1, sumsofar + term!(x, n));
  }
}

/*** Calculate atan(x) at compile time.
 *
 * Uses the Maclaurin formula
 *  atan(z) = z - z^3/3 + Z^5/5 - Z^7/7 + ...
 */
template atan(real z)
{
    const real atan = evaluateSeries!(z, atanTerm);
}

template atanTerm(real x, int n)
{
    const real atanTerm =  (n & 1 ? 1 : -1) * pow!(x, 2*n-1)/(2*n-1);
}

/// Machin's formula for pi
/// pi/4 = 4 atan(1/5) - atan(1/239).
pragma(msg, "PI = " ~ fcvt!(4.0 * (4*atan!(1/5.0) - atan!(1/239.0))) );
Odpowiedział 17/09/2008 o 18:49
źródło użytkownik

głosy
19

Jest to „klasyczny” sposób, bardzo łatwe do wdrożenia. Ta implementacja w Pythonie (nie tak szybko, język) to robi:

from math import pi
from time import time


precision = 10**6 # higher value -> higher precision
                  # lower  value -> higher speed

t = time()

calc = 0
for k in xrange(0, precision):
    calc += ((-1)**k) / (2*k+1.)
calc *= 4. # this is just a little optimization

t = time()-t

print "Calculated: %.40f" % calc
print "Costant pi: %.40f" % pi
print "Difference: %.40f" % abs(calc-pi)
print "Time elapsed: %s" % repr(t)

Możesz znaleźć więcej informacji tutaj .

W każdym razie to najszybszy sposób, aby uzyskać precyzyjne jak-dużo-as-you-want wartość pi w Pythonie jest:

from gmpy import pi
print pi(3000) # the rule is the same as 
               # the precision on the previous code

oto fragment źródła dla gmpy metody pi, nie sądzę, kod jest tak samo użyteczne jak komentarz w tej sprawie:

static char doc_pi[]="\
pi(n): returns pi with n bits of precision in an mpf object\n\
";

/* This function was originally from netlib, package bmp, by
 * Richard P. Brent. Paulo Cesar Pereira de Andrade converted
 * it to C and used it in his LISP interpreter.
 *
 * Original comments:
 * 
 *   sets mp pi = 3.14159... to the available precision.
 *   uses the gauss-legendre algorithm.
 *   this method requires time o(ln(t)m(t)), so it is slower
 *   than mppi if m(t) = o(t**2), but would be faster for
 *   large t if a faster multiplication algorithm were used
 *   (see comments in mpmul).
 *   for a description of the method, see - multiple-precision
 *   zero-finding and the complexity of elementary function
 *   evaluation (by r. p. brent), in analytic computational
 *   complexity (edited by j. f. traub), academic press, 1976, 151-176.
 *   rounding options not implemented, no guard digits used.
*/
static PyObject *
Pygmpy_pi(PyObject *self, PyObject *args)
{
    PympfObject *pi;
    int precision;
    mpf_t r_i2, r_i3, r_i4;
    mpf_t ix;

    ONE_ARG("pi", "i", &precision);
    if(!(pi = Pympf_new(precision))) {
        return NULL;
    }

    mpf_set_si(pi->f, 1);

    mpf_init(ix);
    mpf_set_ui(ix, 1);

    mpf_init2(r_i2, precision);

    mpf_init2(r_i3, precision);
    mpf_set_d(r_i3, 0.25);

    mpf_init2(r_i4, precision);
    mpf_set_d(r_i4, 0.5);
    mpf_sqrt(r_i4, r_i4);

    for (;;) {
        mpf_set(r_i2, pi->f);
        mpf_add(pi->f, pi->f, r_i4);
        mpf_div_ui(pi->f, pi->f, 2);
        mpf_mul(r_i4, r_i2, r_i4);
        mpf_sub(r_i2, pi->f, r_i2);
        mpf_mul(r_i2, r_i2, r_i2);
        mpf_mul(r_i2, r_i2, ix);
        mpf_sub(r_i3, r_i3, r_i2);
        mpf_sqrt(r_i4, r_i4);
        mpf_mul_ui(ix, ix, 2);
        /* Check for convergence */
        if (!(mpf_cmp_si(r_i2, 0) && 
              mpf_get_prec(r_i2) >= (unsigned)precision)) {
            mpf_mul(pi->f, pi->f, r_i4);
            mpf_div(pi->f, pi->f, r_i3);
            break;
        }
    }

    mpf_clear(ix);
    mpf_clear(r_i2);
    mpf_clear(r_i3);
    mpf_clear(r_i4);

    return (PyObject*)pi;
}

EDIT: Miałem pewne problemy z wycinania i wklejania i wcięć, i tak można znaleźć źródło tutaj .

Odpowiedział 02/10/2008 o 22:27
źródło użytkownik

głosy
13

Ta wersja (w Delphi) to nic specjalnego, ale jest przynajmniej szybciej niż w wersji Nick Hodge pisał na swoim blogu :). Na moim komputerze, trwa około 16 sekund, aby zrobić miliard iteracji, co daje wartość 3,14159265 25879 (dokładna część jest pogrubione).

program calcpi;

{$APPTYPE CONSOLE}

uses
  SysUtils;

var
  start, finish: TDateTime;

function CalculatePi(iterations: integer): double;
var
  numerator, denominator, i: integer;
  sum: double;
begin
  {
  PI may be approximated with this formula:
  4 * (1 - 1/3 + 1/5 - 1/7 + 1/9 - 1/11 .......)
  //}
  numerator := 1;
  denominator := 1;
  sum := 0;
  for i := 1 to iterations do begin
    sum := sum + (numerator/denominator);
    denominator := denominator + 2;
    numerator := -numerator;
  end;
  Result := 4 * sum;
end;

begin
  try
    start := Now;
    WriteLn(FloatToStr(CalculatePi(StrToInt(ParamStr(1)))));
    finish := Now;
    WriteLn('Seconds:' + FormatDateTime('hh:mm:ss.zz',finish-start));
  except
    on E:Exception do
      Writeln(E.Classname, ': ', E.Message);
  end;
end.
Odpowiedział 12/01/2009 o 19:24
źródło użytkownik

głosy
20

Właśnie natknąłem się na ten jeden, który powinien być tutaj dla kompletności:

obliczyć PI w Piet

Ma dość ładny obiekt, że precyzja może ulec poprawie dzięki czemu program większe.

Tutaj „s pewien wgląd w samego języka

Odpowiedział 12/01/2009 o 19:46
źródło użytkownik

głosy
12

Już w dawnych czasach, z niewielkimi rozmiarami słownych i operacji powolnych lub nieistniejących zmiennoprzecinkowych, zwykliśmy robić rzeczy tak:

/* Return approximation of n * PI; n is integer */
#define pi_times(n) (((n) * 22) / 7)

W przypadku aplikacji, które nie wymagają dużo precyzji (gry wideo, na przykład), to jest bardzo szybki i jest wystarczająco dokładne.

Odpowiedział 20/02/2009 o 22:21
źródło użytkownik

głosy
15

Pi jest dokładnie 3! [Prof. Frink (Simpsonowie)]

Żart, ale tutaj jest jeden w języku C # (.NET Framework jest wymagany).

using System;
using System.Text;

class Program {
    static void Main(string[] args) {
        int Digits = 100;

        BigNumber x = new BigNumber(Digits);
        BigNumber y = new BigNumber(Digits);
        x.ArcTan(16, 5);
        y.ArcTan(4, 239);
        x.Subtract(y);
        string pi = x.ToString();
        Console.WriteLine(pi);
    }
}

public class BigNumber {
    private UInt32[] number;
    private int size;
    private int maxDigits;

    public BigNumber(int maxDigits) {
        this.maxDigits = maxDigits;
        this.size = (int)Math.Ceiling((float)maxDigits * 0.104) + 2;
        number = new UInt32[size];
    }
    public BigNumber(int maxDigits, UInt32 intPart)
        : this(maxDigits) {
        number[0] = intPart;
        for (int i = 1; i < size; i++) {
            number[i] = 0;
        }
    }
    private void VerifySameSize(BigNumber value) {
        if (Object.ReferenceEquals(this, value))
            throw new Exception("BigNumbers cannot operate on themselves");
        if (value.size != this.size)
            throw new Exception("BigNumbers must have the same size");
    }

    public void Add(BigNumber value) {
        VerifySameSize(value);

        int index = size - 1;
        while (index >= 0 && value.number[index] == 0)
            index--;

        UInt32 carry = 0;
        while (index >= 0) {
            UInt64 result = (UInt64)number[index] +
                            value.number[index] + carry;
            number[index] = (UInt32)result;
            if (result >= 0x100000000U)
                carry = 1;
            else
                carry = 0;
            index--;
        }
    }
    public void Subtract(BigNumber value) {
        VerifySameSize(value);

        int index = size - 1;
        while (index >= 0 && value.number[index] == 0)
            index--;

        UInt32 borrow = 0;
        while (index >= 0) {
            UInt64 result = 0x100000000U + (UInt64)number[index] -
                            value.number[index] - borrow;
            number[index] = (UInt32)result;
            if (result >= 0x100000000U)
                borrow = 0;
            else
                borrow = 1;
            index--;
        }
    }
    public void Multiply(UInt32 value) {
        int index = size - 1;
        while (index >= 0 && number[index] == 0)
            index--;

        UInt32 carry = 0;
        while (index >= 0) {
            UInt64 result = (UInt64)number[index] * value + carry;
            number[index] = (UInt32)result;
            carry = (UInt32)(result >> 32);
            index--;
        }
    }
    public void Divide(UInt32 value) {
        int index = 0;
        while (index < size && number[index] == 0)
            index++;

        UInt32 carry = 0;
        while (index < size) {
            UInt64 result = number[index] + ((UInt64)carry << 32);
            number[index] = (UInt32)(result / (UInt64)value);
            carry = (UInt32)(result % (UInt64)value);
            index++;
        }
    }
    public void Assign(BigNumber value) {
        VerifySameSize(value);
        for (int i = 0; i < size; i++) {
            number[i] = value.number[i];
        }
    }

    public override string ToString() {
        BigNumber temp = new BigNumber(maxDigits);
        temp.Assign(this);

        StringBuilder sb = new StringBuilder();
        sb.Append(temp.number[0]);
        sb.Append(System.Globalization.CultureInfo.CurrentCulture.NumberFormat.CurrencyDecimalSeparator);

        int digitCount = 0;
        while (digitCount < maxDigits) {
            temp.number[0] = 0;
            temp.Multiply(100000);
            sb.AppendFormat("{0:D5}", temp.number[0]);
            digitCount += 5;
        }

        return sb.ToString();
    }
    public bool IsZero() {
        foreach (UInt32 item in number) {
            if (item != 0)
                return false;
        }
        return true;
    }

    public void ArcTan(UInt32 multiplicand, UInt32 reciprocal) {
        BigNumber X = new BigNumber(maxDigits, multiplicand);
        X.Divide(reciprocal);
        reciprocal *= reciprocal;

        this.Assign(X);

        BigNumber term = new BigNumber(maxDigits);
        UInt32 divisor = 1;
        bool subtractTerm = true;
        while (true) {
            X.Divide(reciprocal);
            term.Assign(X);
            divisor += 2;
            term.Divide(divisor);
            if (term.IsZero())
                break;

            if (subtractTerm)
                this.Subtract(term);
            else
                this.Add(term);
            subtractTerm = !subtractTerm;
        }
    }
}
Odpowiedział 26/02/2009 o 20:22
źródło użytkownik

głosy
21

Zamiast definiować pi jako stała, zawsze używać acos(-1).

Odpowiedział 08/03/2009 o 04:02
źródło użytkownik

głosy
11

Metoda Brent pisał powyżej Chris jest bardzo dobra; Brent ogólnie jest gigantem w dziedzinie duże liczby całkowite.

Jeśli chcesz to n-ty cyfra, słynna formuła BBP jest przydatna w hex

Odpowiedział 04/08/2009 o 22:39
źródło użytkownik

głosy
15

Jeśli są chętni do korzystania przybliżenie, 355 / 113jest dobre dla 6 cyfr po przecinku, a ma tę dodatkową zaletę, że jest użyteczny z wyrażeń całkowitych. To nie jest tak ważne w dzisiejszych czasach, jak „zmiennoprzecinkowych koprocesor matematyczny” przestały mieć jakiekolwiek znaczenie, ale to było bardzo ważne raz.

Odpowiedział 17/09/2009 o 17:30
źródło użytkownik

głosy
51

W trosce o kompletność, C ++ wersja szablonu, który dla zoptymalizowanej budowie będzie obliczyć PI w czasie kompilacji i wbudować do jednej wartości.

#include <iostream>

template<int I>
struct sign
{
    enum {value = (I % 2) == 0 ? 1 : -1};
};

template<int I, int J>
struct pi_calc
{
    inline static double value ()
    {
        return (pi_calc<I-1, J>::value () + pi_calc<I-1, J+1>::value ()) / 2.0;
    }
};

template<int J>
struct pi_calc<0, J>
{
    inline static double value ()
    {
        return (sign<J>::value * 4.0) / (2.0 * J + 1.0) + pi_calc<0, J-1>::value ();
    }
};


template<>
struct pi_calc<0, 0>
{
    inline static double value ()
    {
        return 4.0;
    }
};

template<int I>
struct pi
{
    inline static double value ()
    {
        return pi_calc<I, I>::value ();
    }
};

int main ()
{
    std::cout.precision (12);

    const double pi_value = pi<10>::value ();

    std::cout << "pi ~ " << pi_value << std::endl;

    return 0;
}

Uwaga dla I> 10, zoptymalizowany buduje może być powolny, podobnie jak dla przebiegów niezoptymalizowanych. Przez 12 iteracji Wierzę, że istnieje około 80k rozmowy do wartości () (w przypadku braku memoisation).

Odpowiedział 22/12/2009 o 16:40
źródło użytkownik

głosy
12

Jeśli chcesz obliczyć przybliżenie wartości Õ (z jakiegoś powodu), należy spróbować algorytm ekstrakcji binarny. Bellard jest poprawa BBP daje nie PI w O (N ^ 2).


Jeśli chcesz uzyskać przybliżenie wartości Õ zrobić obliczenia, a następnie:

PI = 3.141592654

To prawda, że jest tylko przybliżeniem, a nie do końca dokładne. To się przez trochę ponad +0,00000000004102. (cztery TEN-trillionths, około 4 / 10000000000 ).


Jeśli chcesz zrobić matematyki z Õ, a następnie dostać się papier i ołówek lub pakietu komputer algebry i użyć dokładną wartość gatunku, w π.

Jeśli naprawdę chcesz formuły, ten jest zabawa:

π = - I ln (1)

Odpowiedział 22/12/2009 o 22:13
źródło użytkownik

głosy
20

Jeśli ten artykuł jest prawdą, to algorytm, który Bellard stworzył może być jednym z najszybszą dostępny. On stworzył PI 2,7 biliona cyfr za pomocą komputera stacjonarnego!

... i opublikował swoją pracę tutaj

Dobra praca Bellard, Jesteś pionierem!

http://www.theregister.co.uk/2010/01/06/very_long_pi/

Odpowiedział 06/01/2010 o 13:41
źródło użytkownik

głosy
15

Dzięki podwójnej:

4.0 * (4.0 * Math.Atan(0.2) - Math.Atan(1.0 / 239.0))

To będzie dokładna do 14 miejsc po przecinku, wystarczy wypełnić podwójna (niedokładność jest prawdopodobnie dlatego, że reszta po przecinku w stycznych łukowych są obcinane).

Również Seth, to +3,14159265358979323846 3 , a nie 64.

Odpowiedział 28/02/2010 o 04:52
źródło użytkownik

głosy
15

Za pomocą takiego wzoru Machin-

176 * arctan (1/57) + 28 * arctan (1/239) - 48 * arctan (1/682) + 96 * arctan(1/12943) 

[; \left( 176 \arctan \frac{1}{57} + 28 \arctan \frac{1}{239} - 48 \arctan \frac{1}{682} + 96 \arctan \frac{1}{12943}\right) ;], for you TeX the World people.

Realizowane na schemacie, na przykład:

(+ (- (+ (* 176 (atan (/ 1 57))) (* 28 (atan (/ 1 239)))) (* 48 (atan (/ 1 682)))) (* 96 (atan (/ 1 12943))))

Odpowiedział 05/02/2011 o 06:26
źródło użytkownik

głosy
36

Poniższe odpowiedzi dokładnie, jak to zrobić w najszybszy możliwy sposób - przy jak najmniejszym wysiłku obliczeniowej . Nawet jeśli nie podoba ci się odpowiedź, trzeba przyznać, że jest to rzeczywiście najszybszy sposób, aby uzyskać wartość PI.

Najszybszy sposób, aby uzyskać wartość PI:

  1. wybrał swój ulubiony język programowania
  2. To załadować biblioteki Math
  3. i okaże się, że Pi jest już zdefiniowana tam !! gotowy do użycia ..

w przypadku, gdy nie masz pod ręką biblioteki Math ..

drugim najszybciej sposób (bardziej uniwersalne rozwiązanie) jest:

look up Pi w Internecie, np tutaj:

http://www.eveandersson.com/pi/digits/1000000 (1 milion cyfr .. jaka jest twoja zmiennoprzecinkowa precyzja?)

lub tu:

http://3.141592653589793238462643383279502884197169399375105820974944592.com/

lub tu:

http://en.wikipedia.org/wiki/Pi

To naprawdę szybko znaleźć cyfry potrzebne do precyzyjnego arytmetyka cokolwiek chcesz używać, a przez określenie stałej, można mieć pewność, że nie tracić cennego czasu procesora.

Nie tylko jest to częściowo humorystyczny odpowiedź, ale w rzeczywistości, jeśli ktoś pójdzie do przodu i obliczyć wartość Pi w rzeczywistej aplikacji .. byłoby to dość duża strata czasu procesora, prawda? Przynajmniej ja nie widzę prawdziwy wniosek próbuje to ponownie obliczyć.

Szanowny Moderator: należy pamiętać, że PO zapytał: „najszybszy sposób , aby uzyskać wartość PI”

Odpowiedział 28/10/2011 o 02:02
źródło użytkownik

głosy
1

Obliczanie gatunku z obszaru okręgu :-)

<input id="range" type="range" min="10" max="960" value="10" step="50" oninput="calcPi()">
<br>
<div id="cont"></div>

<script>
function generateCircle(width) {
    var c = width/2;
    var delta = 1.0;
    var str = "";
    var xCount = 0;
    for (var x=0; x <= width; x++) {
        for (var y = 0; y <= width; y++) {
            var d = Math.sqrt((x-c)*(x-c) + (y-c)*(y-c));
            if (d > (width-1)/2) {
                str += '.';
            }
            else {
                xCount++;
                str += 'o';
            }
            str += "&nbsp;" 
        }
        str += "\n";
    }
    var pi = (xCount * 4) / (width * width);
    return [str, pi];
}

function calcPi() {
    var e = document.getElementById("cont");
    var width = document.getElementById("range").value;
    e.innerHTML = "<h4>Generating circle...</h4>";
    setTimeout(function() {
        var circ = generateCircle(width);
        e.innerHTML  = "<pre>" + "π = " + circ[1].toFixed(2) + "\n" + circ[0] +"</pre>";
    }, 200);
}
calcPi();
</script>

Odpowiedział 03/06/2017 o 17:13
źródło użytkownik

głosy
0

lepszym rozwiązaniem

Aby uzyskać wyjście standardowych stałych takich jak pi lub standardowych pojęć, powinniśmy najpierw pójść z dostępnych metod język, który używasz poleceń wbudowanych. Zwróci wartość w najszybszy sposób i najlepszy sposób również. Używam Pythona aby uzyskać najszybszy sposób, aby uzyskać wartość pi

  • pi zmienna biblioteki matematycznej . Biblioteka matematyczna przechowywać zmienna pi jako stała.

math_pi.py

import math
print math.pi

Uruchom skrypt za pomocą narzędzia czasu linux /usr/bin/time -v python math_pi.py

Wydajność:

Command being timed: "python math_pi.py"
User time (seconds): 0.01
System time (seconds): 0.01
Percent of CPU this job got: 91%
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.03
  • Użyj łuku cos metody matematyki

acos_pi.py

import math
print math.acos(-1)

Uruchom skrypt za pomocą narzędzia czasu linux /usr/bin/time -v python acos_pi.py

Wydajność:

Command being timed: "python acos_pi.py"
User time (seconds): 0.02
System time (seconds): 0.01
Percent of CPU this job got: 94%
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.03

bbp_pi.py

from decimal import Decimal, getcontext
getcontext().prec=100
print sum(1/Decimal(16)**k * 
          (Decimal(4)/(8*k+1) - 
           Decimal(2)/(8*k+4) - 
           Decimal(1)/(8*k+5) -
           Decimal(1)/(8*k+6)) for k in range(100))

Uruchom skrypt za pomocą narzędzia czasu linux /usr/bin/time -v python bbp_pi.py

Wydajność:

Command being timed: "python c.py"
User time (seconds): 0.05
System time (seconds): 0.01
Percent of CPU this job got: 98%
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.06

Więc najlepszym sposobem jest użycie builtins metody zalecanej przez przyczynę języka są one najszybciej i najlepiej, aby uzyskać wyjście. W Pythonie użytku Math.PI

Odpowiedział 18/06/2018 o 10:07
źródło użytkownik

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more