¿Cuál es la forma más rápida de obtener el valor de π?

votos
275

Estoy buscando la forma más rápida de obtener el valor de π, como un desafío personal. Más específicamente, estoy usando formas que no implican el uso de #defineconstantes como M_PI, o el código duro en el número.

El siguiente programa prueba las diversas formas que conozco. La versión de ensamblaje en línea es, en teoría, la opción más rápida, aunque claramente no portátil. Lo he incluido como referencia para comparar con las otras versiones. En mis pruebas, con built-ins, la 4 * atan(1)versión es más rápida en GCC 4.2, ya que la dobla automáticamente atan(1)en una constante. Con -fno-builtinespecificado, la atan2(0, -1)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 las cosas de ensamblaje en línea ( fldpi.c) que solo funcionarán para los sistemas x86 y x64:

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

Y un script de compilación que construye 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 probar entre varios indicadores del compilador (también comparé 32 bit con 64 bit, porque las optimizaciones son diferentes), también intenté cambiar el orden de las pruebas. Pero aún así, la atan2(0, -1)versión sigue siendo excelente cada vez.

Publicado el 01/08/2008 a las 06:21
fuente por usuario
En otros idiomas...                            


23 respuestas

votos
72

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, además de que le enseña el concepto de métodos "Monte-Carlo", que son métodos estadísticos para llegar a respuestas que no parecen ser inmediatamente deducible a través de procesos aleatorios.

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

Ahora lanza un dardo en el cuadrado y registra dónde aterriza, 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 verá que hay una proporción de la cantidad de puntos dentro del semicírculo en comparación con el número total arrojado, llame a esta relación x.

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

Este no es un método rápido de usar. Pero es un buen ejemplo de un método de Monte Carlo. Y si miras a tu alrededor, es posible que encuentres muchos problemas fuera de tus habilidades computacionales que pueden resolverse con esos métodos.

Respondida el 01/08/2008 a las 14:37
fuente por usuario

votos
180

El método de Monte Carlo , como se mencionó, aplica algunos conceptos geniales pero, claramente, no es el más rápido, ni por lejos, ni por una medida razonable. Además, todo depende del tipo de precisión que estés buscando. El π más rápido que conozco es el que tiene los dígitos codificados. Mirando 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 actual, usa esta fórmula con FFT . Escribiré la fórmula, ya que el código es directo. Esta fórmula casi fue encontrada por Ramanujan y descubierta por Chudnovsky . De hecho, es la forma en que calculó varios miles de millones de dígitos del número, por lo que no es un método para ignorar. La fórmula se desbordará rápidamente y, dado que estamos dividiendo los factores, sería ventajoso retrasar dichos cálculos para eliminar los términos.

enter image description here

enter image description here

dónde,

enter image description here

A continuación se muestra el algoritmo de Brent-Salamin . Wikipedia menciona que cuando a y b son "lo suficientemente cerca", entonces (a + b) ² / 4t será una aproximación de π. No estoy seguro de qué significa "lo suficientemente cerca", pero de 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 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 poco de golf pi (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);}
Respondida el 02/08/2008 a las 19:22
fuente por usuario

votos
17

Si por el más rápido quieres decir más rápido para escribir el código, aquí está la solución de golfscript :

;''6666,-2%{2+.2/@*\/10.3??2*+}*`1000<~\;
Respondida el 06/08/2008 a las 23:54
fuente por usuario

votos
40

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

Estudié la AGM y los algoritmos relacionados un poco: 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 multiprecision ( GMP es una muy buena opción, aunque ha pasado un tiempo desde la última vez que la usé).

La complejidad de tiempo de los mejores algoritmos está en O (M (n) log (n)), donde M (n) es la complejidad de tiempo para la multiplicación de dos enteros de n bits (M (n) = O (n) log (n) log (log (n))) utilizando algoritmos basados ​​en FFT, que generalmente se necesitan 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í mismos son generalmente unas pocas líneas de pseudocódigo, y su implementación suele ser muy sencilla (si elige no escribir su propia aritmética de multiprecision :-)).

Respondida el 24/08/2008 a las 18:14
fuente por usuario

votos
25

La fórmula BBP le permite calcular el enésimo dígito - en la base 2 (o 16) - sin tener que molestarse siquiera con los n-1 dígitos anteriores primero :)

Respondida el 29/08/2008 a las 10:22
fuente por usuario

votos
96

Me gusta mucho este programa, que se aproxima pi al mirar su propia á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()
{
            _-_-_-_
       _-_-_-_-_-_-_-_-_
    _-_-_-_-_-_-_-_-_-_-_-_
  _-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
  _-_-_-_-_-_-_-_-_-_-_-_-_-_
    _-_-_-_-_-_-_-_-_-_-_-_
        _-_-_-_-_-_-_-_
            _-_-_-_
}
Respondida el 02/09/2008 a las 14:28
fuente por usuario

votos
15

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))) );
Respondida el 17/09/2008 a las 18:49
fuente por usuario

votos
19

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)

Puede 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á la fuente para el 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;
}

EDIT: tuve un problema con cortar y pegar y la identación, de todos modos puede encontrar la fuente aquí .

Respondida el 02/10/2008 a las 22:27
fuente por usuario

votos
13

Esta versión (en Delphi) no es nada especial, pero es al menos más rápida que la versión que Nick Hodge publicó en su blog :). En mi máquina, toma alrededor de 16 segundos hacer mil millones de iteraciones, dando un valor de 3.14159265 25879 (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.
Respondida el 12/01/2009 a las 19:24
fuente por usuario

votos
20

Acabo de encontrar este que debería estar aquí para completarlo:

calcular PI en Piet

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

Aquí hay una idea del lenguaje en sí

Respondida el 12/01/2009 a las 19:46
fuente por usuario

votos
12

En los viejos tiempos, con pequeños tamaños de palabras y operaciones de coma 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 es lo suficientemente preciso.

Respondida el 20/02/2009 a las 22:21
fuente por usuario

votos
15

Pi es exactamente 3! [Profe. Frink (Simpsons)]

Broma, pero aquí hay una 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;
        }
    }
}
Respondida el 26/02/2009 a las 20:22
fuente por usuario

votos
21

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

Respondida el 08/03/2009 a las 04:02
fuente por usuario

votos
11

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

Si todo lo que quieres es el dígito N-ésimo, la famosa fórmula BBP es útil en hex.

Respondida el 04/08/2009 a las 22:39
fuente por usuario

votos
15

Si está dispuesto a usar una aproximación, 355 / 113es válido para 6 dígitos decimales y tiene la ventaja adicional de ser utilizable con expresiones enteras. Eso no es tan importante en estos días, ya que el "coprocesador matemático de coma flotante" dejó de tener sentido, pero fue bastante importante una vez.

Respondida el 17/09/2009 a las 17:30
fuente por usuario

votos
51

En aras de la exhaustividad, una versión de la plantilla C ++, que para una construcción optimizada calculará PI en tiempo de compilación y será en línea para un ú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, optimizado construye puede ser lenta, así como para tiradas no optimizadas. Durante 12 iteraciones Creo que hay alrededor de 80k llamadas a valor () (en ausencia de memoisation).

Respondida el 22/12/2009 a las 16:40
fuente por usuario

votos
12

Si desea calcular una aproximación del valor de π (por alguna razón), se debe tratar de un algoritmo de extracción binario. De Bellard mejora de BBP da hace PI en O (N ^ 2).


Si desea obtener una aproximación del valor de π para hacer cálculos, a continuación:

PI = 3.141592654

Por supuesto, eso es sólo una aproximación, y no del todo precisa. Está fuera por un poco más de ,00000000004102. (cuatro de diez trillonésimas, sobre 4 / 10000000000 ).


Si usted quiere hacer matemáticas con π, entonces se consigue un lápiz y papel o un paquete de álgebra computacional, y utilizar el valor exacto de π, π.

Si realmente quieres una fórmula, ésta es divertido:

π = - i ln (-1)

Respondida el 22/12/2009 a las 22:13
fuente por usuario

votos
20

Si este artículo es cierto, entonces el algoritmo que Bellard ha creado podría ser una de las más rápida disponible. Él ha creado pi a 2,7 billones de dígitos utilizando un PC de escritorio!

... y ha publicado su trabajo aquí

Buen trabajo Bellard, Usted es un pionero!

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

Respondida el 06/01/2010 a las 13:41
fuente por usuario

votos
15

Con dobles:

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

Esta será exacta hasta 14 cifras decimales, lo suficiente como para llenar una habitación doble (la inexactitud es probablemente debido a que el resto de los decimales en las tangentes de arco se truncan).

También Seth, es 3,14159265358979323846 3 , no 64.

Respondida el 28/02/2010 a las 04:52
fuente por usuario

votos
15

Usa la fórmula Machin-como

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 el Esquema, por ejemplo:

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

Respondida el 05/02/2011 a las 06:26
fuente por usuario

votos
36

Las siguientes respuestas con precisión cómo hacer esto de la manera más rápida posible - con el menor esfuerzo de computación . Incluso si no te gusta la respuesta, hay que admitir que es de hecho la forma más rápida de obtener el valor de PI.

La forma más rápida para obtener el valor de Pi es:

  1. eligió su lenguaje de programación favorito
  2. cargarlo de biblioteca matemática
  3. y encontrar que Pi ya está definido allí !! listo para usarlo ..

en caso de que no tiene una biblioteca de matemáticas en la mano ..

el segundo mejor manera (solución más universal) es:

mirar hacia arriba Pi en Internet, por ejemplo aquí:

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

o aquí:

http://3.141592653589793238462643383279502884197169399375105820974944592.com/

o aquí:

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

Es muy rápido para encontrar los dígitos que necesita para cualquier aritmética de precisión que le gustaría usar, y definiendo una constante, puede asegurarse de que usted no pierda tiempo de CPU preciosa.

Esto no sólo es en parte una respuesta humorística, pero en realidad, si alguien iba a seguir adelante y calcular el valor de Pi en una aplicación real .. eso sería una muy gran pérdida de tiempo de CPU, ¿verdad? Por lo menos yo no veo una aplicación real para tratar de volver a calcular esto.

Estimado Moderador: Tenga en cuenta que el PO preguntó: "Manera más rápida para obtener el valor de PI"

Respondida el 28/10/2011 a las 02:02
fuente por usuario

votos
1

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

Respondida el 03/06/2017 a las 14:13
fuente por usuario

votos
0

mejor Approach

Para obtener la salida de las constantes estándar como pi o los conceptos estándar, lo primero que debe ir con los métodos disponibles builtins el idioma que se está utilizando. Se devolverá el valor de la manera más rápida y mejor manera también. Estoy usando Python para obtener la forma más rápida de obtener el valor de pi

  • variables pi de la biblioteca matemática . Biblioteca matemática pi almacenar la variable como constante.

math_pi.py

import math
print math.pi

Ejecutar la secuencia de comandos con la utilidad momento de Linux /usr/bin/time -v python math_pi.py

Salida:

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 arco cos método de matemáticas

acos_pi.py

import math
print math.acos(-1)

Ejecutar la secuencia de comandos con la utilidad momento de Linux /usr/bin/time -v python acos_pi.py

Salida:

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

Ejecutar la secuencia de comandos con la utilidad momento de Linux /usr/bin/time -v python bbp_pi.py

Salida:

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

Así que mejor manera es usar órdenes internas método proporcionado por la causa idioma que son los más rápidos y mejor para obtener la salida. En Python uso math.pi

Respondida el 18/06/2018 a las 10:07
fuente por usuario

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