2008-09-02 22 views
22

¿Cómo puedo calcular el valor de PI usando C#?¿Cómo calculo PI en C#?

Estaba pensando que sería a través de una función recursiva, si es así, ¿cómo se vería y hay alguna ecuación matemática para respaldarlo?

No soy demasiado quisquilloso con el rendimiento, principalmente sobre cómo hacerlo desde el punto de vista del aprendizaje.

+0

[Esta pregunta] (http://stackoverflow.com/questions/19/fastest-way-to -get-value-of-pi) tiene un montón de buenas soluciones desde una perspectiva algorítmica. No creo que sea difícil adaptar uno de ellos a C#. –

Respuesta

40

Si quieres recursividad:

PI = 2 * (1 + 1/3 * (1 + 2/5 * (1 + 3/7 * (...)))) 

Esto se convertiría, después de algún reescritura:

PI = 2 * F(1); 

con F (i):

double F (int i) { 
    return 1 + i/(2.0 * i + 1) * F(i + 1); 
} 

Isaac Newton (que puede tener oído hablar de él antes;)) se le ocurrió este truco. Tenga en cuenta que dejé fuera la condición final, para hacerlo simple. En la vida real, necesitas una.

+0

Además, ¿necesita devolver un valor? – JFA

+3

@jack No tiene una condición de terminación o un valor de retorno. Si desea crear un ejemplo de trabajo completo, le sugiero que publique una nueva respuesta.Ver el comentario en la respuesta 'Tenga en cuenta que omití la condición final, para mantenerlo simple. En la vida real, de alguna manera necesitas uno. – dcaswell

+4

¿Cómo es que esto tiene tantos upvotes? esto no devuelve ** nada ** – Guy

1

Calcular la siguiente manera:

x = 1 - 1/3 + 1/5 - 1/7 + 1/9 (... etc as far as possible.) 
PI = x * 4 

tienes Pi !!!

Este es el método más simple que conozco.

El valor de PI converge lentamente al valor real de Pi (3.141592165 ......). Si iteras más veces, mejor.

20

Cómo sobre el uso:

double pi = Math.PI; 

Si desea una mejor precisión que eso, usted tendrá que utilizar un sistema algorítmico y el tipo Decimal.

+3

Creo que es un caso raro cuando necesitaría tener más precisión de la que obtendría de Math.PI; –

+1

En estos casos, no puede usar el doble pero necesita una biblioteca para números de precisión arbitrarios. – CodesInChaos

+0

En pi day y en pi hackaton necesitaré más precisión que esto. – wtsang02

0

En cualquier escenario de producción, le obligaría a buscar el valor, al número deseado de puntos decimales, y almacenarlo como un 'const' en algún lugar donde sus clases puedan acceder a él.

(a menos que usted está escribiendo software específico científica 'Pi' ...)

+0

Un comentario sobre el voto a favor me ayuda a entender lo que hice mal. Ahora tengo que adivinar. Tal vez eres un científico informático descontento que no aprecia mi enfoque pragmático. No considera que responda al espíritu de la pregunta "cómo hacerlo desde el punto de vista del aprendizaje". Aunque lo debato porque mi respuesta es la solución más eficaz. –

+0

La pregunta era pedir un algoritmo para encontrar pi, no cómo usar el valor de pi – iedoc

4

una buena visión general de los diferentes algoritmos:

No estoy seguro acerca de la complejidad reclamada para el algoritmo Gauss-Legendre-Salamin en el primer enlace (Diría que O (N log^2 (N) log (log (N)))) .

Lo animo a que lo intente, sin embargo, la convergencia es realmente rápido.

Además, no estoy muy seguro de por qué tratar de convertir un algoritmo de procedimiento bastante simple en uno recursivo?

Tenga en cuenta que si está interesado en el rendimiento, entonces trabajar con una precisión limitada (generalmente, que requiere una salida "doble", "flotante", ...) realmente no tiene sentido, como la respuesta obvia en tal caso es solo para codificar el valor.

-8
public double PI = 22.0/7.0; 
+7

PI == 3.14159 ... 22.0/7.0 == 3.14285 ... Difícilmente una respuesta precisa. –

+2

-1 la pregunta era pedir un método para fines educativos, no un valor, y 22/7 es una aproximación pobre en cualquier caso. –

0

En cuanto a ...

... cómo ir sobre ella desde el punto de vista del aprendizaje.

¿Estás tratando de aprender a programar métodos científicos? o para producir software de producción? Espero que la comunidad vea esto como una pregunta válida y no como una trampa.

En cualquier caso, creo que escribir su propio Pi es un problema resuelto. Dmitry mostró la constante 'Math.PI' ya. ¡Ataque otro problema en el mismo espacio! Busque aproximaciones genéricas de Newton o algo ingenioso.

1

Aquí hay un buen enfoque (desde the main Wikipedia entry on pi); converge mucho más rápido que la fórmula simple discutida anteriormente, y es bastante susceptible a una solución recursiva si tu intención es buscar la recursividad como un ejercicio de aprendizaje. (Suponiendo que buscas la experiencia de aprendizaje, no estoy dando ningún código real.)

La fórmula subyacente es la misma que la anterior, pero este enfoque promedia las sumas parciales para acelerar la convergencia.

definir una función dos parámetros, pastel (h, w), tal que:

pie(0,1) = 4/1 
pie(0,2) = 4/1 - 4/3 
pie(0,3) = 4/1 - 4/3 + 4/5 
pie(0,4) = 4/1 - 4/3 + 4/5 - 4/7 
... and so on 

Así que su primera oportunidad de explorar recursión es codificar que la computación "horizontal", como el "ancho" aumentos de parámetros (para "altura" de cero).

A continuación, añadir la segunda dimensión con esta fórmula:

pie(h, w) = (pie(h-1,w) + pie(h-1,w+1))/2 

que se utiliza, por supuesto, sólo para valores de h mayor que cero.

Lo bueno de este algoritmo es que puedes simularlo fácilmente con una hoja de cálculo para verificar tu código mientras exploras los resultados producidos por parámetros progresivamente más grandes. Para cuando calcule el pastel (10,10), tendrá un valor aproximado para pi que sea lo suficientemente bueno para la mayoría de los propósitos de ingeniería.

2

¿Qué es PI? La circunferencia de un círculo dividido por su diámetro.

En gráficos por computadora puede trazar/dibujar un círculo con su centro en 0,0 desde un punto inicial x, y, el siguiente punto x ', y' se puede encontrar usando una fórmula simple: x '= x + y/h: y '= y - x'/h

h suele ser una potencia de 2, de modo que la división se puede hacer fácilmente con un cambio (o restar del exponente en un doble). h también quiere ser el radio r de tu círculo. Un punto de inicio fácil sería x = r, y = 0, y luego contar c el número de pasos hasta x < = 0 para trazar un quater de un círculo. PI es 4 * c/r o PI es 4 * c/h

La recursión a cualquier profundidad, generalmente no es práctica para un programa comercial, pero la recursividad de cola permite que un algoritmo se exprese recursivamente, mientras se implementa como un bucle.Los algoritmos de búsqueda recursiva a veces se pueden implementar utilizando una cola en lugar de la pila del proceso, la búsqueda tiene que dar marcha atrás desde un punto muerto y tomar otra ruta: estos puntos de retroceso se pueden poner en cola y varios procesos pueden deshacer los puntos e intentar otros caminos

6

Hay un par de trucos realmente muy viejos que estoy sorprendido de no ver aquí.

atan (1) == PI/4, por lo que una castaña vieja cuando una función de arco tangente confiable es presente es 4 * atan (1).

Una estimación muy linda, de proporción fija que hace que el viejo Western 22/7 parezca suciedad es 355/113, lo cual es bueno con varios decimales (al menos tres o cuatro, creo). En algunos casos, esto es incluso suficiente para la aritmética de enteros: multiplique por 355 y luego divida por 113.

355/113 también es fácil de memorizar (para algunas personas de todos modos): cuente uno, uno, tres, tres, cinco, cinco y recuerde que está nombrando los dígitos en el denominador y el numerador (si olvida qué triplete va arriba, el pensamiento de un microsegundo generalmente lo va a arreglar).

Tenga en cuenta que 22/7 le da: 3.14285714, que está mal en las milésimas.

355/113 le da 3.14159292 que no está mal hasta las diez millonésimas.

Acc. Para /usr/include/math.h en mi casilla, M_PI está # definido como: 3.14159265358979323846 que probablemente sea bueno hasta donde llegue.

La lección que se obtiene de la estimación de PI es que hay muchas maneras de hacerlo, ninguna será perfecta alguna vez, y tiene que ordenarlas por el uso previsto.

355/113 es una antigua estimación china, y creo que es anterior a 22/7 por muchos años. Me lo enseñó un profesor de física cuando era estudiante.

0

@Thomas Kammeyer:

Tenga en cuenta que Atan (1.0) está codificado con bastante frecuencia, por lo que 4 * Atan (1.0) no es realmente un 'algoritmo' si está llamando una función de biblioteca Atan (un buen algunos ya sugeridos proceden de hecho reemplazando Atan (x) por una serie (o producto infinito), y luego lo evalúan en x = 1.

También, hay muy pocos casos en los que necesitaría pi a más precisión de algunas decenas de bits (que se puede codificar fácilmente!). He trabajado en aplicaciones en matemáticas donde, para calcular algunos objetos matemáticos (bastante complicados) (que eran polinomios con coeficientes enteros), tuvo que hacer aritmética en números reales y complejos (incluyendo el cálculo de pi) con una precisión de hasta unos pocos millones de bits ... pero esto no es muy frecuente 'en la vida real' :)

Puedes buscar lo siguiente ejemplo code.

1
Enumerable.Range(0, 100000000).Aggregate(0d, (tot, next) => tot += Math.Pow(-1d, next)/(2*next + 1)*4) 
+0

En realidad, si prueba con 100000000, devuelve 3,14159264358933, lo cual es incorrecto. Si elimina un 0 (10000000), devuelve 3,14159265358979 que está bien. El ataque de la operación de punto flotante de nuevo? –

6

Si usted toma una mirada cercana a esta muy buena guía:

Patterns for Parallel Programming: Understanding and Applying Parallel Patterns with the .NET Framework 4

que encontrará en la página 70 de este lindo aplicación (con pequeños cambios de mi lado):

static decimal ParallelPartitionerPi(int steps) 
{ 
    decimal sum = 0.0; 
    decimal step = 1.0/(decimal)steps; 
    object obj = new object(); 

    Parallel.ForEach(
     Partitioner.Create(0, steps), 
     () => 0.0, 
     (range, state, partial) => 
     { 
      for (int i = range.Item1; i < range.Item2; i++) 
      { 
       decimal x = (i - 0.5) * step; 
       partial += 4.0/(1.0 + x * x); 
      } 

      return partial; 
     }, 
     partial => { lock (obj) sum += partial; }); 

    return step * sum; 
} 
+3

+1 enfoque interesante que es muy rápido. Pero más allá del hecho de que esto no se compila como está (puedo editarlo si lo desea), tampoco funciona. De todos modos, mi punto es, una vez que lo haces bien y el valor parece 'parecerse' a PI, echa un vistazo más profundo y verás que los últimos decimales que da son bastante imprecisos y ... cambian para cada carrera. La versión * doble * del documento tiene el mismo problema, pero el * decimal * no es más preciso. –

0

Me gusta this paper, que explica cómo calcular π basado en una expansión de la serie Taylor para Arctangent.

El documento comienza con la simple suposición de que

Atan (1) = π/4 radianes

Atan (x) puede ser estimado de forma iterativa con la serie de Taylor

atan (x) = x - x^3/3 + x^5/5 - x^7/7 + x^9/9 ...

El documento señala por qué esto no es particularmente eficiente y continúa con una serie de mejoras lógicas en la técnica. También proporcionan un programa de ejemplo que calcula π a unos pocos miles de dígitos, completo con código fuente, incluidas las rutinas matemáticas de precisión infinita requeridas.

+0

Y mientras estés allí, mira el _awesome_ fractal generator :) –

1
using System; 

namespace Strings 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 

/*   decimal pie = 1; 
      decimal e = -1; 
*/ 
      var stopwatch = new System.Diagnostics.Stopwatch(); 
      stopwatch.Start(); //added this nice stopwatch start routine 

    //leibniz formula in C# - code written completely by Todd Mandell 2014 
/* 
      for (decimal f = (e += 2); f < 1000001; f++) 
      { 
       e += 2; 
       pie -= 1/e; 
       e += 2; 
       pie += 1/e; 
       Console.WriteLine(pie * 4); 
      } 

       decimal finalDisplayString = (pie * 4); 
       Console.WriteLine("pie = {0}", finalDisplayString); 
       Console.WriteLine("Accuracy resulting from approximately {0} steps", e/4); 
*/ 

// Nilakantha formula - code written completely by Todd Mandell 2014 
// π = 3 + 4/(2*3*4) - 4/(4*5*6) + 4/(6*7*8) - 4/(8*9*10) + 4/(10*11*12) - (4/(12*13*14) etc 

      decimal pie = 0; 
      decimal a = 2; 
      decimal b = 3; 
      decimal c = 4; 
      decimal e = 1; 

      for (decimal f = (e += 1); f < 100000; f++) 
      // Increase f where "f < 100000" to increase number of steps 
      { 

       pie += 4/(a * b * c); 

       a += 2; 
       b += 2; 
       c += 2; 

       pie -= 4/(a * b * c); 

       a += 2; 
       b += 2; 
       c += 2; 

       e += 1; 
      } 

      decimal finalDisplayString = (pie + 3); 
      Console.WriteLine("pie = {0}", finalDisplayString); 
      Console.WriteLine("Accuracy resulting from {0} steps", e); 

      stopwatch.Stop(); 
      TimeSpan ts = stopwatch.Elapsed; 
      Console.WriteLine("Calc Time {0}", ts); 

      Console.ReadLine(); 

     } 
    } 
} 
1
public static string PiNumberFinder(int digitNumber) 
    { 
     string piNumber = "3,"; 
     int dividedBy = 11080585; 
     int divisor = 78256779; 
     int result; 

     for (int i = 0; i < digitNumber; i++) 
     { 
      if (dividedBy < divisor) 
       dividedBy *= 10; 

      result = dividedBy/divisor; 

      string resultString = result.ToString(); 
      piNumber += resultString; 

      dividedBy = dividedBy - divisor * result; 
     } 

     return piNumber; 
    } 
0

En primer lugar, tenga en cuenta que C# se puede utilizar el campo Math.PI del marco .NET:

https://msdn.microsoft.com/en-us/library/system.math.pi(v=vs.110).aspx

La característica interesante aquí es que se trata de un doble precisión que completa puede usar o comparar con resultados calculados. Las pestañas en esa URL tienen constantes similares para C++, F # y Visual Basic.

Para calcular más lugares, puede escribir su propio código de precisión extendida. Uno que es rápido para codificar y razonablemente rápido y fácil de programar es:

Pi = 4 * [* 4 arctan (1/5) - arctan (1/239)]

Esta fórmula y muchos otros, incluyendo algunos que convergen en tasas sorprendentemente rápido, tal como 50 dígitos por término, están en Wolfram:

Wolfram Pi Formulas