Wat is de snelste manier om de waarde van π te krijgen?

stemmen
275

Ik ben op zoek naar de snelste manier om de waarde van π te verkrijgen, als een persoonlijke uitdaging. Meer in het bijzonder, gebruik ik een manier die niet met behulp van inhouden #defineconstanten, zoals M_PIof het hard coderen van het nummer in.

De onderstaande programma test de verschillende manieren die ik ken. De inline assemblage-versie is, in theorie, de snelste optie, maar duidelijk niet draagbaar. Ik heb het opgenomen als een basislijn te vergelijken ten opzichte van de andere versies. In mijn tests, met ingebouwde-ins, de 4 * atan(1)versie is het snelst op GCC 4.2, omdat het auto-vouwt de atan(1)in een constante. Met -fno-builtinopgegeven, is de atan2(0, -1)versie is het snelst.

Hier is het belangrijkste testprogramma ( 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;
}

En de inline assemblage stuff ( fldpi.c), die alleen werkt voor x86 en x64-systemen:

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

En een build script dat alle configuraties bouwt Ik test ( 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

Naast het testen tussen verschillende compiler vlaggen (ik heb ten opzichte van 32-bit tegen de 64-bit ook, omdat de optimalisaties zijn verschillend), Ik heb ook geprobeerd het schakelen van de volgorde van de tests rond. Maar toch, de atan2(0, -1)versie komt nog steeds uit op de top elke keer.

De vraag is gesteld op 01/08/2008 om 06:21
bron van user
In andere talen...                            


23 antwoorden

stemmen
180

De Monte Carlo methode , zoals gezegd, niet de snelste geldt een aantal grote concepten, maar het is duidelijk, en niet door een long shot, niet door een redelijke maatregel. Ook, het hangt allemaal af van wat voor soort van nauwkeurigheid die u zoekt. De snelste π ik van weet is degene met de cijfers hard gecodeerd. Kijkend naar Pi en Pi [PDF] , zijn er een heleboel formules.

Hier is een methode die snel convergeert - ongeveer 14 cijfers per iteratie. PiFast de huidige snelste toepassing gebruikt deze formule met de FFT . Ik zal gewoon schrijf de formule, omdat de code is eenvoudig. Deze formule werd bijna gevonden door Ramanujan en ontdekt door Chudnovsky . Het is eigenlijk hoe hij berekend enkele miljarden cijfers van het nummer - dus het is niet een methode om te negeren. De formule snel overstromen en aangezien we delende factorials, zou het voordelig zijn dan zulke berekeningen termen verwijderen vertragen.

voer image beschrijving hier

voer image beschrijving hier

waar,

voer image beschrijving hier

Hieronder vindt u de Brent-Salamin algoritme . Wikipedia vermeldt dat wanneer a en b zijn "dichtbij genoeg" dan (a + b) ² / 4t zal een benadering van π zijn. Ik weet niet zeker wat "dicht genoeg" betekent, maar van mijn tests, een iteratie kreeg 2 cijfers, twee kregen 7, en drie hadden 15, dat is natuurlijk met doubles, dus het zou kunnen een fout op basis van de vertegenwoordiging en de ware berekening zou nauwkeuriger.

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)

Tot slot, wat dacht je van een aantal pi golf (800 cijfers)? 160 tekens!

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);}
antwoordde op 02/08/2008 om 19:22
bron van user

stemmen
96

Ik hou echt van dit programma, dat pi benadert door te kijken naar zijn eigen gebied :-)

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()
{
            _-_-_-_
       _-_-_-_-_-_-_-_-_
    _-_-_-_-_-_-_-_-_-_-_-_
  _-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
  _-_-_-_-_-_-_-_-_-_-_-_-_-_
    _-_-_-_-_-_-_-_-_-_-_-_
        _-_-_-_-_-_-_-_
            _-_-_-_
}
antwoordde op 02/09/2008 om 14:28
bron van user

stemmen
72

Hier is een algemene beschrijving van een techniek voor het berekenen van pi die ik geleerd op de middelbare school.

Ik dit deel alleen omdat ik denk dat het is eenvoudig genoeg dat iedereen het kan herinneren, voor onbepaalde tijd, plus het leert je het concept van de "Monte-Carlo" methoden - die statistische methoden om te komen tot antwoorden die niet direct lijken te zijn, zijn af te leiden door middel van willekeurige processen.

Teken een vierkant, en teken een kwadrant (een kwart van een halve cirkel) in dat veld (een kwadrant met een straal gelijk aan de zijde van het vierkant, zodat het vult zoveel mogelijk van de haaks mogelijk)

Nu gooi een dart op het plein, en noteer waar het landt - dat is, kies dan een willekeurig punt ergens in het plein. Natuurlijk, het landde in het vierkant, maar is het in de halve cirkel? Noteer dit feit.

Herhaal dit proces vele malen - en u zult merken dat er een verhouding van het aantal punten in de halve cirkel ten opzichte van het totale aantal gegooid, noemen deze verhouding x.

Aangezien het oppervlak van het vierkante r r maal, kan afleiden dat het gebied van de halve cirkel x maal r r keer (dat wil zeggen, x maal r kwadraat). Vandaar dat X keer 4 zul je pi geven.

Dit is niet een snelle methode om te gebruiken. Maar het is een mooi voorbeeld van een Monte Carlo methode. En als je kijkt rond, zult u merken dat veel problemen op een andere manier buiten uw rekenvaardigheden kan worden opgelost door dergelijke methoden.

antwoordde op 01/08/2008 om 14:37
bron van user

stemmen
51

In het belang van de volledigheid, een C ++ template versie, die voor een geoptimaliseerde build zal PI berekenen tijdens het compileren en zal inline om een ​​enkele waarde.

#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;
}

Noot voor I> 10, geoptimaliseerd bouwt kan langzaam, ook voor niet-geoptimaliseerde runs. Voor 12 iteraties geloof dat ik er ongeveer 80k oproepen om waarde () (in de afwezigheid van memoization).

antwoordde op 22/12/2009 om 16:40
bron van user

stemmen
40

Er is eigenlijk een heel boek gewijd (onder andere) om snel methoden voor de berekening van \ pi: 'Pi en de AGM', door Jonathan en Peter Borwein ( beschikbaar op Amazon ).

Ik bestudeerde de AVA en de bijbehorende algoritmen nogal wat: het is heel interessant (hoewel soms niet-triviale).

Merk op dat voor de uitvoering van de meeste moderne algoritmen te berekenen \ pi, vindt u een mulitprecisie rekenkundige bibliotheek nodig ( GMP is een heel goede keuze, maar het is alweer een tijdje geleden dat ik voor het laatst gebruikt).

De tijd complexiteit van de beste methoden is in O (M (n) log (n)), waarbij M (n) de tijd-complexiteit voor vermenigvuldiging van twee n-bit getallen (M (n) = O (n log (n) log (log (n))) met behulp van FFT-gebaseerde algoritmen, die meestal nodig bij het berekenen van de cijfers \ pi en dergelijk algoritme wordt geïmplementeerd in GMP).

Merk op dat hoewel de wiskunde achter de algoritmes niet triviaal zou kunnen zijn, de algoritmes zelf zijn meestal een paar regels van pseudo-code, en de uitvoering ervan is meestal zeer eenvoudig (als je ervoor kiest je eigen mulitprecisie rekenkunde niet te schrijven :-)).

antwoordde op 24/08/2008 om 18:14
bron van user

stemmen
36

De volgende antwoorden precies hoe dit te doen in de snelst mogelijke manier - met de minste berekenen inspanning . Zelfs als je niet van het antwoord, je moet toegeven dat het inderdaad de snelste manier om te krijgen van de waarde van PI.

De snelste manier om de waarde van Pi te krijgen is:

  1. kies uw favoriete programmeertaal
  2. laden Math bibliotheek
  3. en vinden dat Pi er al gedefinieerd is !! klaar om het te gebruiken ..

in het geval u niet beschikt over een Math bibliotheek bij de hand ..

de tweede snelste weg (universeler oplossing) is:

opzoeken Pi op het internet, bijvoorbeeld hier:

http://www.eveandersson.com/pi/digits/1000000 (1 miljoen cijfers .. wat is je floating point precisie?)

of hier:

http://3.141592653589793238462643383279502884197169399375105820974944592.com/

of hier:

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

Het is echt snel om de cijfers die u nodig hebt om wat voor precisie rekenkunde die u zou willen gebruiken, en door het definiëren van een constante, kunt u ervoor zorgen dat u geen kostbare CPU-tijd te verspillen.

Niet alleen is dit een gedeeltelijk humoristische antwoord, maar in werkelijkheid, als iemand zou doorgaan en berekenen van de waarde van Pi in een echte applicatie .. dat zou een vrij grote verspilling van CPU-tijd te zijn, zou het niet? Tenminste ik heb geen echte applicatie te zien voor het proberen om opnieuw te berekenen dit.

Geachte Moderator: let er op dat de OP vroeg: "snelste manier om de waarde van PI te krijgen"

antwoordde op 28/10/2011 om 02:02
bron van user

stemmen
25

De BBP formule kunt u de n-cijferige berekenen - in basis 2 (of 16) - zonder zelfs moeite met de vorige n-1 cijfers eerste :)

antwoordde op 29/08/2008 om 10:22
bron van user

stemmen
21

In plaats van het definiëren van pi als een constante, gebruik ik altijd acos(-1).

antwoordde op 08/03/2009 om 04:02
bron van user

stemmen
20

Als dit artikel waar is, dan is het algoritme dat Bellard heeft gecreëerd zou een van de snelste beschikbare. Hij heeft pi geschapen tot 2,7 biljoen cijfers met behulp van een desktop-PC!

... en hij heeft zijn gepubliceerde werk hier

Goed werk Bellard, U bent een pionier!

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

antwoordde op 06/01/2010 om 13:41
bron van user

stemmen
20

Net kwam deze degene die hier moet worden voor de volledigheid:

berekenen PI Piet

Het heeft de nogal mooie eigenschap dat de nauwkeurigheid kan worden verbeterd waardoor het programma groter.

Hier 's enig inzicht in de taal zelf

antwoordde op 12/01/2009 om 19:46
bron van user

stemmen
19

Dit is een "klassieke" methode, zeer eenvoudig te implementeren. Deze implementatie, in python (niet zo snel taal) doet het:

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)

U kunt meer informatie vinden hier .

Hoe dan ook de snelste manier om een ​​nauwkeurig-veel-as-you-want waarde van pi te krijgen in python is:

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

hier is het stuk van de bron voor de gmpy pi methode, ik denk niet dat de code is net zo goed bruikbaar als het commentaar in deze zaak:

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: Ik had een probleem met knippen en plakken en identation, toch kun je de bron te vinden hier .

antwoordde op 02/10/2008 om 22:27
bron van user

stemmen
17

Als door snelste je bedoelt snelste te typen in de code, hier is de golfscript oplossing:

;''6666,-2%{2+.2/@*\/10.3??2*+}*`1000<~\;
antwoordde op 06/08/2008 om 23:54
bron van user

stemmen
15

Met de Machin-achtige formule

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.

Geïmplementeerd in Schema bijvoorbeeld:

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

antwoordde op 05/02/2011 om 06:26
bron van user

stemmen
15

Met doubles:

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

Deze zijn nauwkeurig tot 14 decimalen, genoeg om een ​​dubbele vullen (onnauwkeurigheid komt waarschijnlijk omdat de rest van de decimalen in de boog raaklijnen afgekapt).

Ook Seth, het is 3,14159265358979323846 3 , niet 64.

antwoordde op 28/02/2010 om 04:52
bron van user

stemmen
15

Als u bereid bent om een benadering te gebruiken, 355 / 113is goed voor 6 decimale cijfers, en heeft als bijkomend voordeel dat het bruikbaar is met integer uitdrukkingen. Dat is niet zo belangrijk deze dagen, als "floating point math co-processor" opgehouden enige betekenis hebben, maar het was heel belangrijk keer.

antwoordde op 17/09/2009 om 17:30
bron van user

stemmen
15

Pi is precies 3! [Prof. Frink (Simpsons)]

Joke, maar hier is een in C # (.NET Framework nodig).

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;
        }
    }
}
antwoordde op 26/02/2009 om 20:22
bron van user

stemmen
15

Bereken PI tijdens het compileren met D.

(Gekopieerd van 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))) );
antwoordde op 17/09/2008 om 18:49
bron van user

stemmen
13

Deze versie (in Delphi) is niets bijzonders, maar het is in ieder geval sneller dan de versie die Nick Hodge geplaatst op zijn blog :). Op mijn machine, duurt het ongeveer 16 seconden om een miljard iteraties doen, waardoor een waarde van 3,14159265 25879 (de juiste deel is vetgedrukt).

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.
antwoordde op 12/01/2009 om 19:24
bron van user

stemmen
12

Als u wilt berekenen een benadering van de waarde van π (om wat voor reden), moet u proberen een binair extractie algoritme. Bellard's verbeteren BBP geeft doet PI O (N ^ 2).


Als u wilt krijgen een benadering van de waarde van π om berekeningen te doen, dan:

PI = 3.141592654

Toegegeven, dat is slechts een benadering, en niet helemaal correct. Het is uitgeschakeld door een iets meer dan ,00000000004102. (vier tien trillionths ongeveer 4 / 10000000000 ).


Als u wilt doen wiskunde met π, dan krijg je een potlood en papier of een computer algebra pakket, en het gebruik van π de exacte waarde, π.

Als je echt wilt een formule, deze is leuk:

π = - i ln (-1)

antwoordde op 22/12/2009 om 22:13
bron van user

stemmen
12

Terug in de oude dagen, met kleine woord maten en langzame of non-existent floating-point operaties, hebben we gebruikt om dingen te doen als dit:

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

Voor toepassingen die niet veel precisie vereisen (video games, bijvoorbeeld), dit is zeer snel en is nauwkeurig genoeg.

antwoordde op 20/02/2009 om 22:21
bron van user

stemmen
11

Brent's methode geplaatst bovenaf door Chris is zeer goed; Brent algemeen een reus in het gebied van willekeurige precisie rekenkunde.

Als alles wat je wilt is de N-cijfer, de beroemde BBP formule is nuttig in hex

antwoordde op 04/08/2009 om 22:39
bron van user

stemmen
1

Berekenen van π cirkelgebied :-)

<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>

antwoordde op 03/06/2017 om 17:13
bron van user

stemmen
0

betere aanpak

Om de uitvoer van standaard constanten zoals krijgen pi of de standaard concepten, moeten we eerst gaan met de builtins methoden beschikbaar stellen van de taal die u gebruikt. Het zal waarde in de snelste manier en de beste manier ook terugkeren. Ik gebruik python om de snelste manier om de waarde van pi te krijgen

  • pi variabele van de wiskunde bibliotheek . Math LIBRARY de variabele pi zo constant.

math_pi.py

import math
print math.pi

Voer het script met de tijd nut van linux /usr/bin/time -v python math_pi.py

Output:

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
  • Gebruik cos arc Werkwijze wiskunde

acos_pi.py

import math
print math.acos(-1)

Voer het script met de tijd nut van linux /usr/bin/time -v python acos_pi.py

Output:

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))

Voer het script met de tijd nut van linux /usr/bin/time -v python bbp_pi.py

Output:

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

Dus beste manier is om te gebruiken builtins methode die door de taal want ze zijn de snelste en beste om de uitvoer te krijgen. In python gebruik math.pi

antwoordde op 18/06/2018 om 10:07
bron van user

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