Pregunta

Estoy buscando la manera más rápida de obtener el valor de π, como desafío personal.Más específicamente, estoy usando formas que no implican el uso #define constantes como M_PI, o codificar el número.

El siguiente programa prueba las diversas formas que conozco.La versión ensamblada en línea es, en teoría, la opción más rápida, aunque claramente no es portátil.Lo he incluido como punto de referencia para compararlo con las otras versiones.En mis pruebas, con elementos integrados, el 4 * atan(1) La versión es más rápida en GCC 4.2, porque pliega automáticamente el atan(1) en una constante.Con -fno-builtin especificado, el atan2(0, -1) La versión es más rápida.

Aquí está el programa de prueba 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;
}

Y el material de ensamblaje en línea (fldpi.c) que solo funcionará para sistemas x86 y x64:

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

Y un script de compilación que crea todas las configuraciones que estoy probando (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

Además de realizar pruebas entre varios indicadores del compilador (también he comparado 32 bits con 64 bits porque las optimizaciones son diferentes), también intenté cambiar el orden de las pruebas.Pero aún así, el atan2(0, -1) La versión sigue estando en primer lugar cada vez.

¿Fue útil?

Solución

El Método Montecarlo, como se mencionó, aplica algunos conceptos excelentes pero, claramente, no es el más rápido, ni de lejos, ni de ninguna manera razonable.Además, todo depende del tipo de precisión que busques.El π más rápido que conozco es el que tiene los dígitos codificados.Mirando a Pi y PI[PDF], hay muchas fórmulas.

Aquí hay un método que converge rápidamente: alrededor de 14 dígitos por iteración. PiFast, la aplicación más rápida actualmente, utiliza esta fórmula con la FFT.Simplemente escribiré la fórmula, ya que el código es sencillo.Esta fórmula casi fue encontrada por Ramanujan y descubierto por Chudnovsky.En realidad, así es como calculó varios miles de millones de dígitos del número, por lo que no es un método que deba ignorarse.La fórmula se desbordará rápidamente y, dado que estamos dividiendo factoriales, sería ventajoso retrasar dichos cálculos para eliminar términos.

enter image description here

enter image description here

dónde,

enter image description here

abajo esta el Algoritmo de Brent-Salamina.Wikipedia menciona que cuando a y b están "lo suficientemente cerca" entonces (a+b)²/4t será una aproximación de π.No estoy seguro de lo que significa "lo suficientemente cerca", pero según mis pruebas, una iteración obtuvo 2 dígitos, dos obtuvieron 7 y tres tuvieron 15; por supuesto, esto es con dobles, por lo que podría tener un error basado en su representación y el verdadero El cálculo podría ser más 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, ¿qué tal un 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);}

Otros consejos

Realmente me gusta este programa, porque aproxima π mirando su propia área.

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

Aquí hay una descripción general de una técnica para calcular pi que aprendí en la escuela secundaria.

Solo comparto esto porque creo que es lo suficientemente simple como para que cualquiera pueda recordarlo, indefinidamente, y además te enseña el concepto de los métodos "Monte-Carlo", que son métodos estadísticos para llegar a respuestas que no parecen serlo inmediatamente. deducible mediante procesos aleatorios.

Dibuja un cuadrado e inscribe un cuadrante (un cuarto de semicírculo) dentro de ese cuadrado (un cuadrante con radio igual al lado del cuadrado, de modo que llene la mayor parte del cuadrado posible)

Ahora lanza un dardo al cuadrado y registra dónde cae; es decir, elige un punto aleatorio en cualquier lugar dentro del cuadrado.Por supuesto, aterrizó dentro del cuadrado, pero ¿está dentro del semicírculo?Registre este hecho.

Repita este proceso muchas veces y encontrará que existe una proporción entre el número de puntos dentro del semicírculo y el número total arrojado; llame a esta proporción x.

Dado que el área del cuadrado es r multiplicado por r, puedes deducir que el área del semicírculo es x multiplicado por r multiplicado por r (es decir, x multiplicado por r al cuadrado).Por lo tanto, x multiplicado por 4 te dará pi.

Este no es un método rápido de usar.Pero es un buen ejemplo del método Monte Carlo.Y si miras a tu alrededor, puedes encontrar que muchos problemas que de otro modo estarían fuera de tus habilidades computacionales pueden resolverse mediante tales métodos.

En aras de la integridad, se utilizará una versión de plantilla de C++ que, para una compilación optimizada, calculará una aproximación de PI en el momento de la compilación y se alineará con un valor único.

#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, las compilaciones optimizadas pueden ser lentas, al igual que las ejecuciones no optimizadas.Para 12 iteraciones, creo que hay alrededor de 80.000 llamadas al valor() (en ausencia de memorización).

De hecho, hay un libro completo dedicado (entre otras cosas) a rápido métodos para el cálculo de \pi:'Pi y la AGM', de Jonathan y Peter Borwein (disponible en Amazon).

Estudié bastante el AGM y los algoritmos relacionados:es bastante interesante (aunque a veces no trivial).

Tenga en cuenta que para implementar la mayoría de los algoritmos modernos para calcular \pi, necesitará una biblioteca aritmética de precisión múltiple (BPM es una muy buena elección, aunque ha pasado un tiempo desde la última vez que la usé).

La complejidad temporal de los mejores algoritmos está en O(M(n)log(n)), donde M(n) es la complejidad temporal para la multiplicación de dos enteros de n bits (M(n)=O(n log(n) log(log(n))) usando algoritmos basados ​​en FFT, que generalmente son necesarios al calcular dígitos de \pi, y dicho algoritmo se implementa en GMP).

Tenga en cuenta que, aunque las matemáticas detrás de los algoritmos pueden no ser triviales, los algoritmos en sí suelen consistir en unas pocas líneas de pseudocódigo y su implementación suele ser muy sencilla (si decide no escribir su propia aritmética de multiprecisión :-)).

las siguientes respuestas precisamente cómo hacer esto de la manera más rápida posible, con el menor esfuerzo informático.Incluso si no le gusta la respuesta, debe admitir que, de hecho, es la forma más rápida de obtener el valor de PI.

El LO MÁS RÁPIDO La forma de obtener el valor de Pi es:

1) Elija su lenguaje de programación favorito 2) Cargue su biblioteca de matemáticas 3) y descubra que Pi ya está definido allí, ¡listo para su uso!

En caso de que no tengas una biblioteca de Matemáticas a mano...

El SEGUNDO MÁS RÁPIDO forma (solución más universal) es:

busque Pi en Internet, p.aquí:

http://www.eveandersson.com/pi/digits/1000000 (1 millón de dígitos...¿Cuál es su precisión de coma flotante?)

o aquí:

http://3.141592653589793238462643383279502884197169399375105820974944592.com/

o aquí:

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

Es realmente rápido encontrar los dígitos que necesita para cualquier aritmética de precisión que desee utilizar y, al definir una constante, puede asegurarse de no perder un valioso tiempo de CPU.

Esta no solo es una respuesta en parte humorística, sino que, en realidad, si alguien siguiera adelante y calculara el valor de Pi en una aplicación real...Eso sería una gran pérdida de tiempo de CPU, ¿no?Al menos no veo una aplicación real para intentar volver a calcular esto.

Estimado moderador:tenga en cuenta que el OP preguntó:"La forma más rápida de obtener el valor de PI"

El fórmula BBP le permite calcular el enésimo dígito, en base 2 (o 16), sin tener que preocuparse primero por los n-1 dígitos anteriores :)

En lugar de definir pi como una constante, siempre uso acos(-1).

Acabo de encontrar este que debería estar aquí para que esté completo:

calcular PI en Piet

Tiene la propiedad bastante interesante de que la precisión se puede mejorar haciendo que el programa sea más grande.

AquíEs una idea del lenguaje mismo.

Si Este artículo es cierto, entonces el algoritmo que Bellard ha creado podría ser uno de los más rápidos disponibles.¡Ha creado pi con 2,7 TRILLONES de dígitos usando una PC DE ESCRITORIO!

...y ha publicado su Trabaja aquí

Buen trabajo Bellard, ¡eres un pionero!

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

Este es un método "clásico", muy fácil de implementar.Esta implementación, en Python (lenguaje no tan rápido) lo hace:

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)

Puedes encontrar más información aquí.

De todos modos, la forma más rápida de obtener un valor preciso de pi en Python es:

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

Aquí está el código fuente del método gmpy pi. No creo que el código sea tan útil como el comentario en este 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: Tuve algún problema con cortar y pegar y con la identificación, de todos modos puedes encontrar la fuente. aquí.

Si por más rápido te refieres a escribir el código más rápido, aquí tienes el guión de golf solución:

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

Utilice la fórmula similar 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 en Scheme, por ejemplo:

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

Si está dispuesto a utilizar una aproximación, 355 / 113 es bueno para 6 dígitos decimales y tiene la ventaja adicional de poder usarse con expresiones enteras.Eso no es tan importante hoy en día, ya que "coprocesador matemático de punto flotante" dejó de tener significado, pero alguna vez fue bastante importante.

Con dobles:

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

Esto tendrá una precisión de hasta 14 decimales, suficiente para llenar un doble (la inexactitud probablemente se debe a que el resto de los decimales en los arcos tangentes están truncados).

También Seth, es 3.141592653589793238463, no 64.

Calcule PI en tiempo de compilación con 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 es exactamente 3![Profe.Frink (Los Simpson)]

Broma, pero aquí hay uno en C# (se requiere .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 versión (en Delphi) no es nada especial, pero al menos es más rápida que la versión que Nick Hodge publicó en su blog :).En mi máquina, se necesitan unos 16 segundos para hacer mil millones de iteraciones, lo que da un valor de 3.1415926525879 (la parte exacta está en negrita).

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.

En los viejos tiempos, con tamaños de palabras pequeños y operaciones de punto flotante lentas o inexistentes, solíamos hacer cosas como esta:

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

Para aplicaciones que no requieren mucha precisión (videojuegos, por ejemplo), esto es muy rápido y suficientemente preciso.

Si quieres calcular una aproximación del valor de π (por alguna razón), deberías probar un algoritmo de extracción binaria. Bellardo mejora de BBP da PI en O (N ^ 2).


Si quieres obtener una aproximación del valor de π para hacer cálculos, entonces:

PI = 3.141592654

Por supuesto, eso es sólo una aproximación y no del todo exacta.Tiene una diferencia de poco más de 0,00000000004102.(cuatro diez billonésimas, aproximadamente 4/10,000,000,000).


si quieres hacer matemáticas con π, luego consíguete lápiz y papel o un paquete de álgebra informática y usa el valor exacto de π, π.

Si realmente quieres una fórmula, esta es divertida:

π = -i En(-1)

El método de Brent publicado anteriormente por Chris es muy bueno;Brent en general es un gigante en el campo de la aritmética de precisión arbitraria.

Si lo único que quieres es el enésimo dígito, el famosofórmula BBPes útil en hexadecimal

Calculando π a partir del área del 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>

Mejor enfoque

Para obtener la salida de constantes estándar como Pi Para los conceptos estándar, primero debemos utilizar los métodos integrados disponibles en el lenguaje que estás utilizando.Devolverá valor de la manera más rápida y mejor también.Estoy usando Python para obtener la forma más rápida de obtener el valor pi.

  • variable pi de la biblioteca matemática.La biblioteca matemática almacena la variable pi como constante.

math_pi.py

import math
print math.pi

Ejecute el script con la utilidad de tiempo de Linux /usr/bin/time -v python math_pi.py

Producción:

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
  • Utilice el método matemático arc cos

acos_pi.py

import math
print math.acos(-1)

Ejecute el script con la utilidad de tiempo de Linux /usr/bin/time -v python acos_pi.py

Producción:

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

Ejecute el script con la utilidad de tiempo de Linux /usr/bin/time -v python bbp_pi.py

Producción:

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

Entonces, la mejor manera es utilizar el método integrado proporcionado por el lenguaje porque son los mejores y más rápidos para obtener el resultado.En Python use math.pi

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top