elevar - ¿Cómo calculo PI en C#?
elevar al cuadrado en c# (19)
¿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 es usualmente una potencia de 2, de modo que la división se puede hacer fácilmente con un cambio (o restando 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 grande, por lo general 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
¿Cómo puedo calcular el valor de PI usando 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 muy quisquilloso con el rendimiento, principalmente sobre cómo hacerlo desde el punto de vista del aprendizaje.
@Thomas Kammeyer:
Tenga en cuenta que Atan (1.0) a menudo está codificado, por lo que 4 * Atan (1.0) no es realmente un "algoritmo" si está llamando a una función Atan de la biblioteca (ya se han sugerido algunas sustituyendo Atan (x) por una serie (o producto infinito) para él, luego evaluarlo en x = 1.
Además, hay muy pocos casos en los que necesite pi con más precisión que algunas decenas de bits (¡que pueden codificarse fácilmente!). Trabajé en aplicaciones de matemáticas donde, para calcular algunos objetos matemáticos (bastante complicados) (que eran polinomios con coeficientes enteros), tuve que hacer cálculos aritméticos en números reales y complejos (incluido el cálculo de pi) con una precisión de hasta un pocos millones de bits ... pero esto no es muy frecuente ''en la vida real'' :)
Puede buscar el siguiente código de ejemplo.
Aquí hay un artículo sobre Cálculo de PI en C #:
Aquí hay un buen enfoque (de la entrada principal de Wikipedia en 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.
Defina una función de dos parámetros, pie (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
Por lo tanto, su primera oportunidad para explorar la recursividad es codificar ese cálculo "horizontal" a medida que aumenta el parámetro "ancho" (para "altura" de cero).
A continuación, agregue la segunda dimensión con esta fórmula:
pie(h, w) = (pie(h-1,w) + pie(h-1,w+1)) / 2
que se usa, por supuesto, solo para valores de h mayores 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.
Buena visión general de diferentes algoritmos:
No estoy seguro de la complejidad que se reclama para el algoritmo de Gauss-Legendre-Salamin en el primer enlace (yo diría que O (N log ^ 2 (N) log (log (N)))).
Sin embargo, te animo a probarlo, la convergencia es realmente rápida.
Además, no estoy 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'', ''flotar'', ...) no tiene sentido, ya que la respuesta obvia en tal caso es solo codificar el valor.
Calcule así:
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.
En cualquier escenario de producción, te obligaría a buscar el valor, al número deseado de puntos decimales, y almacenarlo como un ''const'' en algún lugar donde tus clases puedan acceder a él.
(a menos que esté escribiendo un software científico específico de ''Pi'' ...)
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 está presente una función de tangente de arco fiable es 4 * atan (1).
Una estimación muy linda, de proporción fija que hace que el viejo 22/7 occidental parezca suciedad es 355/113, que es bueno para varios decimales (al menos tres o cuatro, creo). En algunos casos, esto es incluso lo suficientemente bueno 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 se va) en la parte superior, 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 te 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 al estimar PI es que hay muchas maneras de hacerlo, ninguna será perfecta y hay que resolverlas según 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.
Respecto a...
... cómo hacerlo 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 tu 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.
Me gusta este artículo , 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) se puede estimar iterativamente 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 haciendo una serie de refinamientos lógicos en la técnica. También proporcionan un programa de ejemplo que calcula π hasta unos pocos miles de dígitos, completo con código fuente, incluidas las rutinas matemáticas de precisión infinita requeridas.
¿Qué hay de usar:
double pi = Math.PI;
Si desea una mayor precisión que eso, necesitará usar un sistema algorítmico y el tipo de Decimal.
public double PI = 22.0 / 7.0;
Enumerable.Range(0, 100000000).Aggregate(0d, (tot, next) => tot += Math.Pow(-1d, next)/(2*next + 1)*4)
El siguiente enlace muestra cómo calcular la constante pi en función de su definición como integral, que se puede escribir como límite de una suma, es muy interesante: https://sites.google.com/site/rcorcs/posts/calculatingthepiconstant El archivo "Pi como integral" explica este método utilizado en esta publicación.
Si le das un vistazo a esta muy buena guía:
Encontrará en la página 70 esta linda implementación (con cambios menores de mi parte):
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;
}
Si quieres recursividad:
PI = 2 * (1 + 1/3 * (1 + 2/5 * (1 + 3/7 * (...))))
Esto se convertiría, después de algunas reescrituras:
PI = 2 * F(1);
con F (i):
double F (int i) {
return 1 + i / (2.0 * i + 1) * F(i + 1);
}
Isaac Newton (es posible que haya oído hablar de él antes;)) se le ocurrió este truco. Tenga en cuenta que omití la condición final, para mantenerlo simple. En la vida real, necesitas una.
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();
}
}
}
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;
}
Primero, tenga en cuenta que C # puede usar el campo Math.PI del framework .NET:
https://msdn.microsoft.com/en-us/library/system.math.pi(v=vs.110).aspx
La buena característica aquí es que es un doble de precisión total que puede usar o comparar con los 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 de codificar y razonablemente rápido y fácil de programar es:
Pi = 4 * [4 * arctan (1/5) - arctan (1/239)]
Esta fórmula y muchas otras, incluidas algunas que convergen a tasas increíblemente rápidas, como 50 dígitos por término, se encuentran en Wolfram: