Pergunta

Procuro a forma mais rápida de obter o valor de π, como um desafio pessoal.Mais especificamente, estou usando formas que não envolvem o uso #define constantes como M_PI, ou codificar o número.

O programa abaixo testa as várias maneiras que conheço.A versão assembly inline é, em teoria, a opção mais rápida, embora claramente não seja portátil.Eu o incluí como base para comparação com as outras versões.Em meus testes, com built-ins, o 4 * atan(1) versão é mais rápida no GCC 4.2, porque dobra automaticamente o atan(1) em uma constante.Com -fno-builtin especificado, o atan2(0, -1) a versão é mais rápida.

Aqui está o programa de teste 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\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;
}

E o material de montagem em linha (fldpi.c) que funcionará apenas para sistemas x86 e x64:

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

E um script de construção que cria todas as configurações que estou testando (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

Além de testar entre vários sinalizadores do compilador (comparei 32 bits com 64 bits também porque as otimizações são diferentes), também tentei mudar a ordem dos testes.Mas ainda assim, o atan2(0, -1) a versão ainda sai por cima sempre.

Foi útil?

Solução

O Método Monte Carlo, como mencionado, aplica alguns conceitos excelentes, mas não é, claramente, o mais rápido, nem de longe, nem de qualquer medida razoável.Além disso, tudo depende do tipo de precisão que você procura.O π mais rápido que conheço é aquele com os dígitos codificados.Olhando para Pi e Pi[PDF], existem muitas fórmulas.

Aqui está um método que converge rapidamente – cerca de 14 dígitos por iteração. PiFast, o aplicativo mais rápido atual, usa esta fórmula com a FFT.Vou apenas escrever a fórmula, já que o código é simples.Esta fórmula quase foi encontrada por Ramanujan e descoberto por Chudnovsky.Na verdade, foi assim que ele calculou vários bilhões de dígitos do número – portanto, não é um método a ser desconsiderado.A fórmula irá transbordar rapidamente e, como estamos dividindo fatoriais, seria vantajoso atrasar tais cálculos para remover termos.

enter image description here

enter image description here

onde,

enter image description here

Abaixo está o Algoritmo Brent-Salamin.A Wikipedia menciona que quando a e b estão "perto o suficiente" então (a + b)² / 4t será uma aproximação de π.Não tenho certeza do que significa "próximo o suficiente", mas pelos meus testes, uma iteração obteve 2 dígitos, duas obtiveram 7 e três tiveram 15, é claro que isso é duplo, então pode haver um erro com base em sua representação e o verdadeiro o cálculo poderia ser mais preciso.

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)

Por último, que tal um pouco de pi golf (800 dígitos)?160 caracteres!

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

Outras dicas

Gosto muito deste programa porque ele aproxima π observando sua própria área.

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()
{
            _-_-_-_
       _-_-_-_-_-_-_-_-_
    _-_-_-_-_-_-_-_-_-_-_-_
  _-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
  _-_-_-_-_-_-_-_-_-_-_-_-_-_
    _-_-_-_-_-_-_-_-_-_-_-_
        _-_-_-_-_-_-_-_
            _-_-_-_
}

Aqui está uma descrição geral de uma técnica para calcular pi que aprendi no ensino médio.

Só compartilho isso porque acho que é simples o suficiente para que qualquer um possa se lembrar dele, indefinidamente, além de ensinar o conceito de métodos de "Monte-Carlo" - que são métodos estatísticos para chegar a respostas que não parecem ser imediatamente possíveis. dedutível através de processos aleatórios.

Desenhe um quadrado e inscreva um quadrante (um quarto de semicírculo) dentro desse quadrado (um quadrante com raio igual ao lado do quadrado, de forma que preencha o máximo possível do quadrado)

Agora jogue um dardo no quadrado e registre onde ele cai - isto é, escolha um ponto aleatório em qualquer lugar dentro do quadrado.Claro, caiu dentro do quadrado, mas será que está dentro do semicírculo?Registre esse fato.

Repita esse processo muitas vezes - e você descobrirá que há uma razão entre o número de pontos dentro do semicírculo e o número total lançado, chame essa razão de x.

Como a área do quadrado é r vezes r, você pode deduzir que a área do semicírculo é x vezes r vezes r (ou seja, x vezes r ao quadrado).Portanto, x vezes 4 lhe dará pi.

Este não é um método rápido de usar.Mas é um bom exemplo de método de Monte Carlo.E se você olhar ao redor, poderá descobrir que muitos problemas que de outra forma estariam fora de suas habilidades computacionais podem ser resolvidos por esses métodos.

No interesse da integridade, uma versão do modelo C++, que, para uma construção otimizada, calculará uma aproximação de PI em tempo de compilação e será incorporada a um único valor.

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

Nota para I> 10, compilações otimizadas podem ser lentas, da mesma forma para execuções não otimizadas.Para 12 iterações, acredito que haja cerca de 80 mil chamadas para value() (na ausência de memorização).

Na verdade, há um livro inteiro dedicado (entre outras coisas) a rápido métodos para o cálculo de \pi:'Pi e a AGM', de Jonathan e Peter Borwein (disponível na Amazon).

Estudei bastante o AGM e algoritmos relacionados:é bastante interessante (embora às vezes não seja trivial).

Observe que para implementar a maioria dos algoritmos modernos para calcular \pi, você precisará de uma biblioteca aritmética de multiprecisão (BPF é uma boa escolha, embora já tenha passado algum tempo desde a última vez que a usei).

A complexidade de tempo dos melhores algoritmos está em O(M(n)log(n)), onde M(n) é a complexidade de tempo para a multiplicação de dois inteiros de n bits (M(n)=O(n log(n) log(log(n))) usando algoritmos baseados em FFT, que geralmente são necessários ao calcular dígitos de \pi, e tal algoritmo é implementado em GMP).

Observe que mesmo que a matemática por trás dos algoritmos possa não ser trivial, os algoritmos em si são geralmente algumas linhas de pseudocódigo e sua implementação geralmente é muito direta (se você optar por não escrever sua própria aritmética de multiprecisão :-)).

As seguintes respostas precisamente como fazer isso da maneira mais rápida possível - com o mínimo esforço computacional.Mesmo que você não goste da resposta, tem que admitir que é de fato a maneira mais rápida de obter o valor do PI.

O O MAIS RÁPIDO maneira de obter o valor de Pi é:

1) Escolha sua linguagem de programação favorita 2) Carregue sua biblioteca de matemática 3) e descobri que o PI já está definido lá - pronto para uso!

Caso você não tenha uma biblioteca de matemática em mãos.

O SEGUNDO MAIS RÁPIDO maneira (solução mais universal) é:

procure Pi na Internet, por ex.aqui:

http://www.eveandersson.com/pi/digits/1000000 (1 milhão de dígitos ..qual é a sua precisão de ponto flutuante?)

ou aqui:

http://3.141592653589793238462643383279502884197169399375105820974944592.com/

ou aqui:

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

É muito rápido encontrar os dígitos necessários para qualquer aritmética de precisão que você gostaria de usar e, ao definir uma constante, você pode ter certeza de não desperdiçar o precioso tempo da CPU.

Esta não é apenas uma resposta parcialmente humorística, mas, na realidade, se alguém fosse em frente e calculasse o valor de Pi em uma aplicação real.isso seria uma grande perda de tempo de CPU, não seria?Pelo menos não vejo uma aplicação real para tentar recalcular isso.

Prezado moderador:observe que o OP perguntou:"A maneira mais rápida de obter o valor do PI"

O Fórmula PAB permite que você calcule o enésimo dígito - na base 2 (ou 16) - sem ter que se preocupar primeiro com os n-1 dígitos anteriores :)

Em vez de definir pi como uma constante, sempre uso acos(-1).

Acabei de encontrar este que deveria estar aqui para completar:

calcular PI em Piet

Tem a propriedade bastante interessante de que a precisão pode ser melhorada tornando o programa maior.

Aquihá algumas dicas sobre a própria linguagem

Se Este artigo é verdade, então o algoritmo que Bellard criou pode ser um dos mais rápidos disponíveis.Ele criou pi com 2,7 TRILHÕES de dígitos usando um PC DESKTOP!

...e ele publicou seu trabalho aqui

Bom trabalho Bellard, você é um pioneiro!

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

Este é um método “clássico” e muito fácil de implementar.Esta implementação, em python (linguagem não tão rápida), faz isso:

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)

Você pode encontrar mais informações aqui.

De qualquer forma, a maneira mais rápida de obter um valor preciso de pi em python é:

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

aqui está a fonte do método gmpy pi, não acho que o código seja tão útil quanto o comentário neste caso:

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

EDITAR: Tive alguns problemas com recortar e colar e identificação, de qualquer forma você pode encontrar a fonte aqui.

Se por mais rápido você quer dizer mais rápido para digitar o código, aqui está o script de golfe solução:

;''6666,-2%{2+.2/@*\/10.3??2*+}*`1000<~\;

Use a fórmula semelhante a 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.

Implementado no esquema, por exemplo:

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

Se você estiver disposto a usar uma aproximação, 355 / 113 é bom para 6 dígitos decimais e tem a vantagem adicional de poder ser usado com expressões inteiras.Isso não é tão importante hoje em dia, já que "coprocessador matemático de ponto flutuante" deixou de ter qualquer significado, mas já foi muito importante.

Com duplas:

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

Isso terá precisão de até 14 casas decimais, o suficiente para preencher um duplo (a imprecisão provavelmente ocorre porque o restante dos decimais nas tangentes do arco estão truncados).

Também Seth, é 3.141592653589793238463, não 64.

Calcule PI em tempo de compilação com D.

(copiado de 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))) );

Pi é exatamente 3![Prof.Frink (Simpsons)]

Piada, mas aqui está uma em C# (requer .NET-Framework).

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

Esta versão (em Delphi) não é nada especial, mas é pelo menos mais rápida que a versão que Nick Hodge postou em seu blog :).Na minha máquina, leva cerca de 16 segundos para fazer um bilhão de iterações, dando um valor de 3.1415926525879 (a parte exata está em negrito).

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.

Antigamente, com palavras pequenas e operações de ponto flutuante lentas ou inexistentes, costumávamos fazer coisas assim:

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

Para aplicações que não exigem muita precisão (videogames, por exemplo), isso é muito rápido e bastante preciso.

Se você quiser calcular uma aproximação do valor de π (por algum motivo), você deve tentar um algoritmo de extração binária. de Bellard Melhoria de BBP dá PI em O (N ^ 2).


Se você quiser obtivermos uma aproximação do valor de π para fazer cálculos, então:

PI = 3.141592654

É verdade que isso é apenas uma aproximação e não totalmente preciso.Está um pouco mais errado que 0,00000000004102.(quatro décimos trilionésimos, cerca de 4/10,000,000,000).


Se você quiser fazer matemática com π, então pegue um lápis e papel ou um pacote de álgebra computacional e use o valor exato de π, π.

Se você realmente quer uma fórmula, esta é divertida:

π = -eu ln(-1)

O método de Brent postado acima por Chris é muito bom;Brent geralmente é um gigante no campo da aritmética de precisão arbitrária.

Se tudo que você quer é o enésimo dígito, o famosoFórmula PABé útil em hexadecimal

Calculando π da área do círculo :-)

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

Melhor abordagem

Para obter a saída de constantes padrão como pi ou os conceitos padrão, devemos primeiro ir com os métodos internos disponíveis na linguagem que você está usando.Ele retornará valor da maneira mais rápida e melhor também.Estou usando python para obter a maneira mais rápida de obter o valor pi

  • variável pi da biblioteca matemática.A biblioteca matemática armazena a variável pi como constante.

matemática_pi.py

import math
print math.pi

Execute o script com o utilitário time do linux /usr/bin/time -v python math_pi.py

Saída:

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
  • Use o método matemático arco cos

acos_pi.py

import math
print math.acos(-1)

Execute o script com o utilitário time do linux /usr/bin/time -v python acos_pi.py

Saída:

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

Execute o script com o utilitário time do linux /usr/bin/time -v python bbp_pi.py

Saída:

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

Portanto, a melhor maneira é usar o método interno fornecido pela linguagem, pois eles são os mais rápidos e melhores para obter a saída.Em python, use math.pi

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top