如何使用C#计算PI的值?
我以为它会通过一个递归函数,如果是这样,它会是什么样子,是否有任何数学方程来支持它?
我对性能不太挑剔,主要是从学习的角度来看它。
答案 0 :(得分:42)
如果你想要递归:
PI = 2 * (1 + 1/3 * (1 + 2/5 * (1 + 3/7 * (...))))
经过一些改写后,这将成为:
PI = 2 * F(1);
与F(i):
double F (int i) {
return 1 + i / (2.0 * i + 1) * F(i + 1);
}
艾萨克·牛顿(你可能以前听说过他;))想出了这个伎俩。
请注意,我省略了最终条件,以保持简单。在现实生活中,你需要一个。
答案 1 :(得分:23)
如何使用:
double pi = Math.PI;
如果你想要更好的精度,你需要使用算法系统和Decimal类型。
答案 2 :(得分:7)
如果你仔细研究这个非常好的指南:
你会发现这个可爱的实现(我身边的细微变化):
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 :(得分:6)
有一些非常非常古老的技巧让我很惊讶,在这里看不到。
atan(1)== PI / 4,所以当一个值得信赖的反正切函数是一个旧栗子 现在是4 * atan(1)。
一个非常可爱,固定比率的估计,使旧西部22/7看起来像泥土 是355/113,这对于几个小数位是好的(我认为至少有三到四个)。 在某些情况下,这甚至可以用于整数运算:乘以355然后除以113。
355/113也很容易记忆(对于某些人来说):计算一,三,三,五,五,并记住你在命名分子和分子中的数字(如果你忘记了)哪一个三元组位于顶部,一微秒的思想通常会使其理顺。)请注意,22/7为您提供:3.14285714,这在千分之一时是错误的。
355/113给你3.14159292,直到百万分之一没有错。
度Acc。到我的盒子上的/usr/include/math.h,M_PI#define'd as: 3.14159265358979323846 这可能是最好的。
从评估PI中得到的教训是,有很多方法可以做到这一点, 没有一个是完美的,你必须按照预期用途对它们进行分类。
355/113是一个古老的中国估计,我相信它在多年前的22/7之前。当我还是一名本科生时,它是由一位物理教授教给我的。答案 4 :(得分:4)
不同算法的良好概述:
我不确定第一个链接中Gauss-Legendre-Salamin算法的复杂性(我说O(N log ^ 2(N)log(log(N)))。
我鼓励你尝试一下,但收敛速度真的快。
另外,我不确定为什么要尝试将一个非常简单的程序算法转换为递归算法?
请注意,如果你对性能感兴趣,那么以有限精度(通常需要'double','float',...输出)工作并不真正有意义,因为在这种情况下明显的答案只是硬编码值。
答案 5 :(得分:3)
以下是关于在C#中计算PI的文章:
答案 6 :(得分:2)
什么是PI?圆周除以直径。
在计算机图形学中,您可以从初始点x,y绘制/绘制一个圆心,其中心位于0,0,可以使用一个简单的公式找到下一个点x',y': x'= x + y / h:y'= y - x'/ h
h通常是2的幂,因此可以通过移位(或从双指数中减去)来轻松完成除法。 h也想成为你圈子的半径r。一个简单的起始点是x = r,y = 0,然后计算c直到x <= 0的步数,以绘制一个圆的四分之一。 PI为4 * c / r或PI为4 * c / h
递归到任何深度,对于商业程序来说通常是不切实际的,但尾递归允许递归地表达算法,同时实现为循环。递归搜索算法有时可以使用队列而不是进程的堆栈来实现,搜索必须从deadend回溯并采用另一条路径 - 这些回溯点可以放入队列,多个进程可以对点进行排队并尝试其他路径。
答案 7 :(得分:1)
Enumerable.Range(0, 100000000).Aggregate(0d, (tot, next) => tot += Math.Pow(-1d, next)/(2*next + 1)*4)
答案 8 :(得分: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;
}
答案 9 :(得分: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();
}
}
}
答案 10 :(得分:1)
像这样计算:
x = 1 - 1/3 + 1/5 - 1/7 + 1/9 (... etc as far as possible.)
PI = x * 4
你有Pi !!!
这是我所知道的最简单的方法。
PI的值慢慢收敛到Pi的实际值(3.141592165 ......)。如果你迭代次数越多越好。
答案 11 :(得分:1)
这是一个很好的方法(来自the main Wikipedia entry on pi);它比上面讨论的简单公式收敛得快得多,并且如果你的意图是将递归作为一种学习练习,它非常适合递归解决方案。 (假设你是在学习经验之后,我没有提供任何实际的代码。)
基本公式与上述相同,但这种方法平均了部分和以加速收敛。
定义一个双参数函数,pie(h,w),这样:
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
因此,您探索递归的第一个机会是将“水平”计算编码为“宽度”参数增加(“高度”为零)。
然后使用以下公式添加第二个维度:
pie(h, w) = (pie(h-1,w) + pie(h-1,w+1)) / 2
当然,仅用于h大于零的值。
这个算法的优点在于,当您浏览逐渐变大的参数所产生的结果时,您可以使用电子表格轻松模拟它以检查代码。当您计算饼图(10,10)时,您将获得pi的近似值,这对于大多数工程目的而言足够好。
答案 12 :(得分:0)
@Thomas Kammeyer:
请注意,Atan(1.0)经常是硬编码的,所以如果你正在调用一个库Atan函数,那么4 * Atan(1.0)并不是真正的'算法'(已经有很多建议确实通过替换Atan来实现) x)通过一系列(或无限产品),然后在x = 1处进行评估。
此外,极少数情况下,您需要的pi精度高于几十位(可以很容易地进行硬编码!)。我已经研究过数学应用程序,为了计算一些(非常复杂的)数学对象(它是带有整数系数的多项式),我不得不对实数和复数(包括计算pi)进行算术运算,精度高达a几百万位......但这在现实生活中并不常见:)
您可以查看以下示例code。
答案 13 :(得分:0)
在任何生产场景中,我都会强迫您查找该值,达到所需的小数点数,并将其存储为您的类可以到达的“const”。
(除非您正在编写科学'Pi'特定软件......)
答案 14 :(得分:0)
以下链接显示了如何基于其定义作为积分来计算pi常量,可以将其写为求和的极限,这非常有趣: https://sites.google.com/site/rcorcs/posts/calculatingthepiconstant 文件“Pi as an integral”解释了这篇文章中使用的方法。
答案 15 :(得分:0)
我喜欢this paper,它解释了如何根据Arctangent的泰勒级数展开计算π。
本文从简单的假设开始
Atan(1)=π/ 4弧度
可以用泰勒级数
迭代估计Atan(x)atan(x)= x - x ^ 3/3 + x ^ 5/5 - x ^ 7/7 + x ^ 9/9 ...
该论文指出了为什么这不是特别有效,并继续在该技术中进行许多逻辑改进。他们还提供了一个示例程序,它将π计算到几千位,包括源代码,包括所需的无限精度数学例程。
答案 16 :(得分:0)
...关于
......如何从学习的角度来看待它。
您是否正在尝试学习科学方法?或者生产生产软件?我希望社区认为这是一个有效的问题,而不是挑剔。
在任何一种情况下,我认为编写自己的Pi是一个已解决的问题。德米特里已经展示了'Math.PI'常数。在同一个空间攻击另一个问题!去寻找通用牛顿近似值或光滑的东西。
答案 17 :(得分:0)
首先,请注意C#可以使用.NET框架的Math.PI字段:
https://msdn.microsoft.com/en-us/library/system.math.pi(v=vs.110).aspx
这里的好功能是它可以使用全精度双精度,或者与计算结果进行比较。该URL的选项卡具有与C ++,F#和Visual Basic类似的常量。
要计算更多地方,您可以编写自己的扩展精度代码。一个代码快速且速度合理且易于编程的方法是:
Pi = 4 * [4 * arctan(1/5) - arctan(1/239)]
这个公式和其他许多公式,包括一些收敛速度惊人的公式,例如每学期50位,都在Wolfram:
答案 18 :(得分:0)
PI(π)可以使用无限系列计算。以下是两个例子:
Gregory-Leibniz系列:
π/ 4 = 1 - 1/3 + 1/5 - 1/7 + 1/9 - ......
C#方法:
public static decimal GregoryLeibnizGetPI(int n)
{
decimal sum = 0;
decimal temp = 0;
for (int i = 0; i < n; i++)
{
temp = 4m / (1 + 2 * i);
sum += i % 2 == 0 ? temp : -temp;
}
return sum;
}
Nilakantha系列:
π= 3 + 4 /(2x3x4) - 4 /(4x5x6)+ 4 /(6x7x8) - 4 /(8x9x10)+ ...
C#方法:
public static decimal NilakanthaGetPI(int n)
{
decimal sum = 0;
decimal temp = 0;
decimal a = 2, b = 3, c = 4;
for (int i = 0; i < n; i++)
{
temp = 4 / (a * b * c);
sum += i % 2 == 0 ? temp : -temp;
a += 2; b += 2; c += 2;
}
return 3 + sum;
}
两个函数的输入参数n
表示迭代次数。
与Gregory-Leibniz系列相比,Nilakantha系列融合得更快。可以使用以下代码测试这些方法:
static void Main(string[] args)
{
const decimal pi = 3.1415926535897932384626433832m;
Console.WriteLine($"PI = {pi}");
//Nilakantha Series
int iterationsN = 100;
decimal nilakanthaPI = NilakanthaGetPI(iterationsN);
decimal CalcErrorNilakantha = pi - nilakanthaPI;
Console.WriteLine($"\nNilakantha Series -> PI = {nilakanthaPI}");
Console.WriteLine($"Calculation error = {CalcErrorNilakantha}");
int numDecNilakantha = pi.ToString().Zip(nilakanthaPI.ToString(), (x, y) => x == y).TakeWhile(x => x).Count() - 2;
Console.WriteLine($"Number of correct decimals = {numDecNilakantha}");
Console.WriteLine($"Number of iterations = {iterationsN}");
//Gregory-Leibniz Series
int iterationsGL = 1000000;
decimal GregoryLeibnizPI = GregoryLeibnizGetPI(iterationsGL);
decimal CalcErrorGregoryLeibniz = pi - GregoryLeibnizPI;
Console.WriteLine($"\nGregory-Leibniz Series -> PI = {GregoryLeibnizPI}");
Console.WriteLine($"Calculation error = {CalcErrorGregoryLeibniz}");
int numDecGregoryLeibniz = pi.ToString().Zip(GregoryLeibnizPI.ToString(), (x, y) => x == y).TakeWhile(x => x).Count() - 2;
Console.WriteLine($"Number of correct decimals = {numDecGregoryLeibniz}");
Console.WriteLine($"Number of iterations = {iterationsGL}");
Console.ReadKey();
}
以下输出显示Nilakantha系列返回六个正确的PI小数,迭代次数为100次,而Gregory-Leibniz系列返回五个正确的小数,包含一百万次迭代:
我的代码可以测试&gt;&gt; here
答案 19 :(得分:0)
这是一个很好的方式: 计算一系列1 / x ^ 2的x从1到你想要的 - 更大的数字 - 更好的馅饼结果。将结果乘以6并将其乘以sqrt()。 这是c#中的代码(仅限主要):
static void Main(string[] args)
{
double counter = 0;
for (double i = 1; i < 1000000; i++)
{
counter = counter + (1 / (Math.Pow(i, 2)));
}
counter = counter * 6;
counter = Math.Sqrt(counter);
Console.WriteLine(counter);
}
答案 20 :(得分:-8)
public double PI = 22.0 / 7.0;