如何在C#中计算PI?

时间:2020-03-05 18:46:24  来源:igfitidea点击:

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

我当时想这将通过递归函数进行,如果是这样,它将是什么样子,是否有任何数学方程式可以支持它?

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

解决方案

回答

计算如下:

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

你有Pi!

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

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

回答

如果要递归:

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

艾萨克·牛顿(我们可能之前曾听说过他;))想出了这个窍门。
请注意,为了简化起见,我省略了结束条件。在现实生活中,我们需要一个。

回答

这是有关在C#中计算PI的文章:

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

回答

如何使用:

double pi = Math.PI;

如果要获得更高的精度,则需要使用算法系统和Decimal类型。

回答

在任何生产场景中,我都会强迫我们将值查找到所需的小数位数,然后将其存储为类可以获取的"常量"。

(除非我们正在编写科学的" Pi"专用软件...)

回答

很好地概述了各种算法:

  • 计算圆周率;
  • 高斯-勒让德雷-萨拉明。

我不确定第一条链路中的Gauss-Legendre-Salamin算法要求的复杂度(我想说O(N log ^ 2(N)log(log(N))))。

我确实鼓励我们尝试一下,但是融合确实非常快。

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

请注意,如果我们对性能感兴趣,那么以有限的精度工作(通常需要" double"," float",...输出)就没有任何意义,因为在这种情况下,显而易见的答案只是硬编码值。

回答

public double PI = 22.0 / 7.0;

回答

关于...

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

我们是否在尝试学习编程科学方法?或者生产生产软件?我希望社区将其视为一个有效的问题,而不是无所作为。

无论哪种情况,我都认为编写自己的Pi是解决的问题。 Dmitry已经显示了'Math.PI'常量。在同一个空间中攻击另一个问题!寻求通用的牛顿近似值或者光滑的东西。

回答

这是一个很好的方法(来自pi上的Wikipedia主条目);它的收敛速度比上面讨论的简单公式快得多,并且如果我们打算将递归作为一种学习活动,则非常适合于递归解决方案。 (假设我们是在学习,那么我没有给出任何实际的代码。)

基本公式与上面的公式相同,但是此方法对部分和求平均以加快收敛。

定义两个参数函数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

因此,探究递归的第一个机会是对"水平"计算进行编码,以使" width"参数增加(" height"为零)。

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

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

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

这种算法的优点是,当我们探索由逐渐增大的参数产生的结果时,可以轻松地使用电子表格对它进行模拟,以检查代码。到计算pie(10,10)时,我们将拥有一个近似的pi值,足以满足大多数工程目的。

回答

什么是PI?圆的周长除以其直径。

在计算机图形学中,我们可以从一个初始点x,y绘制/画一个以0,0为中心的圆,可以使用一个简单的公式找到下一个点x',y':
x'= x + y / h:y'= y x'/ h

h通常是2的幂,因此除法可以轻松地进行移位(或者从double的指数中减去)。 h还想成为圆的半径r。一个简单的起点是x = r,y = 0,然后计算c的步数,直到x <= 0绘制一个四分之一圆。 PI为4 * c / r或者PI为4 * c / h

递归到任何深度都通常对于商业程序是不切实际的,但是尾递归允许算法以循环方式递归表示。有时可以使用队列而不是进程的堆栈来实现递归搜索算法,搜索必须从死角开始回溯,并采用另一条路径可以将这些回溯点放入队列中,并且多个进程可以取消排队这些点并尝试其他路径。

回答

我很惊讶在这里看不到一些非常古老的技巧。

atan(1)== PI / 4,因此当值得信赖的反正切函数为
现在是4 * atan(1)。

一个非常可爱的固定比率估算值,使旧的Western 22/7看起来像土
是355/113,可以精确到小数点后一位(我认为至少3或者4位)。
在某些情况下,这对于整数算术甚至足够好:乘以355,然后除以113.

355/113也很容易提交给内存(无论如何对于某些人来说):数一,一,三,三,五,五,并记住要在分母和分子中命名数字(如果我们忘记了哪个三元组最重要的是,通常需要花费一微秒的时间才能弄清楚它的位置)。

请注意,22/7给我们:3.14285714,这在千分之一中是错误的。

355/113会给我们3.14159292,直到百万分之一秒都没有错。

累积到我的机器上的/usr/include/math.h中,将M_PI定义为:
3.14159265358979323846
就目前而言,这可能是个好选择。

我们可以通过估算PI得到的教训是,有很多方法可以做到这一点,
没有哪一种会是完美的,并且我们必须按预期用途对其进行分类。

355/113是中国的旧估计,我相信它比22/7早很多年。当我还是一个本科的时候,它是由一位物理学教授教给我的。

回答

@托马斯·卡梅尔(Thomas Kammeyer):

请注意,Atan(1.0)通常是经过硬编码的,因此如果我们要调用库Atan函数,则4 * Atan(1.0)并不是一个真正的"算法"(已经建议使用Atan(x)替换Atan(x)的确很多)一个序列(或者无限积),然后在x = 1处对其求值。

另外,在极少数情况下,我们需要pi的精度要高于几十位(可以很容易地对其进行硬编码!)。我从事数学应用程序的研究,要计算一些(相当复杂的)数学对象(具有整数系数的多项式),我必须对实数和复数(包括计算pi)进行算术运算,精度最高为几百万比特...但是在现实生活中这不是很常见:)

我们可以查找以下示例代码。

回答

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

回答

如果我们仔细阅读这份非常好的指南:

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

我们会在第70页中找到这个可爱的实现(我这边做了些微改动):

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;
}