如何在C#中计算PI?

How do I calculate PI in C#?

如何使用C#计算PI的值?

我以为它会通过一个递归函数,如果是这样,它会是什么样子,是否有任何数学公式支持它?

我对性能不太挑剔,主要是从学习的角度来看如何进行。


如果你想要递归:

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

经过一些改写后,这将成为:

1
PI = 2 * F(1);

与F(i):

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

Isaac Newton(你之前可能听说过他;))想出了这个伎俩。
请注意,我省略了最终条件,以保持简单。在现实生活中,你需要一个。


如何使用:

1
double pi = Math.PI;

如果你想要更好的精度,你需要使用算法系统和Decimal类型。


如果你仔细看看这个非常好的指南:

并行编程模式:使用.NET Framework理解和应用并行模式4

你可以在这个可爱的实现中找到(我身边的一些细微变化):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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;
}

有几个非常非常古老的技巧,我很惊讶在这里看不到。

atan(1)== PI / 4,所以当一个值得信赖的反正切函数时,它是一个老栗子
现在是4 * atan(1)。

一个非常可爱,固定比率的估计,使旧西部22/7看起来像泥土
是355/113,这对于几个小数位是好的(我认为至少有三到四个)。
在某些情况下,这甚至足以用于整数运算:乘以355然后除以113。

355/113也容易记忆(对于某些人来说):计算一,三,三,五,五,并记住你在命名分子和分子中的数字(如果你忘了哪个三元组去最重要的是,一微秒的想法通常会把它弄清楚)。

请注意,22/7为您提供:3.14285714,这在千分之一是错误的。

355/113给你3.14159292,直到百万分之一没有错。

加。到我的盒子上的/usr/include/math.h,M_PI#define'd as:
3.14159265358979323846
就目前而言,这可能是好事。

从估算PI中得到的教训是,有很多方法可以做到,
没有一个是完美的,你必须按照预期用途对它们进行分类。

355/113是一个古老的中国估计,我相信它在多年前的22/7之前。当我还是一名本科生时,它是由一位物理教授教给我的。


不同算法的良好概述:

  • 计算pi;
  • 高斯 - 勒 - Salamin。

我不确定第一个链接中Gauss-Legendre-Salamin算法的复杂性(我说O(N log ^ 2(N)log(log(N))))。

我鼓励你尝试一下,但收敛速度非常快。

另外,我不确定为什么尝试将一个非常简单的程序算法转换为递归算法?

请注意,如果您对性能感兴趣,那么以有限精度(通常需要'double','float',...输出)工作并不真正有意义,因为在这种情况下明显的答案就是硬编码值。


这是一篇关于在C#中计算PI的文章:

http://www.boyet.com/Articles/PiCalculator.html


什么是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回溯并采用另一条路径 - 这些回溯点可以放入队列,多个进程可以对点进行排队并尝试其他路径。


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

计算如下:

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

你有Pi !!!

这是我所知道的最简单的方法。

PI的值慢慢收敛到Pi的实际值(3.141592165 ......)。如果迭代次数越多越好。


这是一个很好的方法(来自维基百科的主要条目);它比上面讨论的简单公式收敛得快得多,并且如果你的意图是将递归作为一种学习练习,它非常适合递归解决方案。 (假设你是在学习经验之后,我没有提供任何实际的代码。)

基本公式与上述相同,但这种方法平均部分和以加速收敛。

定义一个双参数函数pie(h,w),这样:

1
2
3
4
5
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

因此,您探索递归的第一个机会是将"水平"计算编码为"宽度"参数增加("高度"为零)。

然后使用以下公式添加第二个维度:

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

当然,它仅用于h大于零的值。

这个算法的优点在于,当您浏览逐渐变大的参数所产生的结果时,您可以使用电子表格轻松模拟它以检查代码。当您计算饼图(10,10)时,您将获得pi的近似值,该值足以满足大多数工程目的。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
    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;
    }

以下链接显示了如何根据其定义作为积分来计算pi常量,可以将其写为求和的极限,这非常有趣:
https://sites.google.com/site/rcorcs/posts/calculatingthepiconstant
文件"Pi as an integral"解释了这篇文章中使用的方法。


这是一个很好的方式:
计算一系列1 / x ^ 2的x从1到你想要的 - 更大的数字 - 更好的馅饼结果。将结果乘以6并将其乘以sqrt()。
这是c#中的代码(仅限主要版本):

1
2
3
4
5
6
7
8
9
10
11
12
13
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);
    }


我喜欢这篇论文,它解释了如何根据Arctangent的泰勒级数展开计算π。

本文从简单的假设开始

Atan(1) = π/4 radians

可以用泰勒级数迭代估计Atan(x)

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

该文件指出了为什么这不是特别有效,并继续在该技术中进行许多逻辑改进。他们还提供了一个示例程序,它将π计算为几千个数字,包含源代码,包括所需的无限精度数学例程。


关于...

... how to go about it from a learning point of view.

您是否正在尝试学习科学方法?或者生产生产软件?我希望社区认为这是一个有效的问题,而不是挑剔。

在任何一种情况下,我认为编写自己的Pi是一个已解决的问题。德米特里已经展示了'Math.PI'常数。在同一个空间攻击另一个问题!去寻找通用牛顿近似值或光滑的东西。


在任何生产场景中,我都会强迫您查找该值,达到所需的小数点数,并将其存储为您的类可以到达的某个"const"。

(除非你正在编写科学的"Pi"特定软件......)


首先,请注意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:

Wolfram Pi Formulas


PI(π)可以通过使用无穷级数来计算。这是两个例子:

格雷戈里 - 莱布尼兹系列:

π/4 = 1 - 1/3 + 1/5 - 1/7 + 1/9 - ...

C#方法:

1
2
3
4
5
6
7
8
9
10
11
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#方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
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系列融合得更快。可以使用以下代码测试这些方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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($"
Nilakantha 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($"
Gregory-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 Series返回六个正确的PI小数,迭代次数为100次,而Gregory-Leibniz Series返回五个正确小数的PI,迭代次数为100次:

enter image description here

我的代码可以在这里测试>>


@Thomas Kammeyer:

请注意,Atan(1.0)经常是硬编码的,所以如果你正在调用一个库Atan函数,那么4 * Atan(1.0)并不是真正的'算法'(已经有很多建议确实通过替换Atan(x)来实现它的一系列(或无限产品),然后在x = 1时评估它。

此外,在极少数情况下,您需要pi的精度高于几十位(可以很容易地硬编码!)。我已经研究过数学应用程序,为了计算一些(非常复杂的)数学对象(它是带有整数系数的多项式),我不得不对实数和复数(包括计算pi)进行算术运算,精度高达a几百万位...但这在现实生活中并不常见':)

您可以查找以下示例代码。


1
public double PI = 22.0 / 7.0;


推荐阅读

    linux支持管道的命令?

    linux支持管道的命令?,通信,标准,系统,信息,地方,数据,管道,环境,设备,工具,L

    linux云计算查看命令?

    linux云计算查看命令?,系统,信息,地址,工作,命令,情况,标准,服务,软件,网络,l

    linux打开计算器命令?

    linux打开计算器命令?,密码,电脑,工作,设备,数字,系统,手机,指数,情况,服务,

    linux命令输出计算?

    linux命令输出计算?,标准,地址,工作,信息,系统,命令,软件,数据,文件,控制台,l

    linux计算总数命令?

    linux计算总数命令?,系统,第一,情况,数据,信息,电脑,命令,百分比,单位,工作,l

    linux中计算器命令?

    linux中计算器命令?,地址,数据,位置,网络,设备,时间,环境,平台,软件,命令,说

    linux性能测试命令?

    linux性能测试命令?,数据,系统,工具,标准,设备,地址,情况,基础,网络,环境,如

    linux退出计算器命令?

    linux退出计算器命令?,工作,地址,系统,命令,通信,信息,电脑,目录,路径,操作,

    重启计算机linux命令?

    重启计算机linux命令?,系统,设备,工作,标准,名称,命令,状态,数据,服务,提示,L

    linux计算器打开命令?

    linux计算器打开命令?,工作,地址,命令,标准,管理,系统,目录,路径,管道,控制

    linux计算摘要的命令?

    linux计算摘要的命令?,数据,网络,数字,密码,工具,名称,正规,标准,代码,文件,l

    linux命令3d性能?

    linux命令3d性能?,系统,工具,实时,百分比,信息,分析,软件,情况,网站,建设,Lin

    linux命令计算时间差?

    linux命令计算时间差?,时间,系统,标准,流程,状态,单位,名称,表达式,命令,时

    linux命令重启计算机?

    linux命令重启计算机?,服务,系统,工作,设备,标准,命令,名称,进程,级别,用户,l

    linux命令计算圆周率?

    linux命令计算圆周率?,代码,圆周率,无理数,直径,比值,表示,圆周,常量,常数,

    linux性能管理命令?

    linux性能管理命令?,工具,系统,信息,状态,网络,情况,工作,时间,短信,平均,lin

    linux性能调参命令?

    linux性能调参命令?,工具,工作,信息,网络,分析,系统,地址,实时,管理,状态,在l

    linux性能找不打命令?

    linux性能找不打命令?,系统,实时,软件,名字,分析,信息,情况,工具,电脑,时间,l