我需要使用以下公式以预定义的精度计算PI:

所以我最终得到了这个解决方案.
private static double CalculatePIWithPrecision(int presicion)
{
if (presicion == 0)
{
return PI_ZERO_PRECISION;
}
double sum = 0;
double numberOfSumElements = Math.Pow(10, presicion + 2);
for (double i = 1; i < numberOfSumElements; i++)
{
sum += 1 / (i * i);
}
double pi = Math.Sqrt(sum * 6);
return pi;
}
Run Code Online (Sandbox Code Playgroud)
所以这是正确的,但我遇到了效率问题.精度值为8或更高时,它非常慢.
是否有更好(更快!)的方法来使用该公式计算PI?
double numberOfSumElements = Math.Pow(10, presicion + 2);
Run Code Online (Sandbox Code Playgroud)
我将严格按照实际的软件工程术语来讨论这个问题,避免迷失在正式的数学中.只是任何软件工程师应该知道的实用技巧.
首先要注意代码的复杂性.执行所需的时间严格取决于此表达式.你已经编写了一个指数算法,随着预算的增加,你计算的值会迅速增加.你引用不舒服的数字,8产生10 ^ 10或一个循环,进行100亿次计算.是的,你注意到这一点,那就是当计算机开始花费几秒钟来产生结果时,无论它们有多快.
指数算法很糟糕,表现很差.只有具有因子复杂度的O(n!),你才能做得更糟.否则许多现实问题的复杂性.
现在,那个表达式真的准确吗?您可以使用实际的背后信息示例进行"肘部测试".让我们选择5位数的精度作为目标并写出来:
1.0000 + 0.2500 + 0.1111 + 0.0625 + 0.0400 + 0.0278 + ... = 1.6433
Run Code Online (Sandbox Code Playgroud)
你可以看出增加的速度越来越小,它会迅速收敛.您可以推断,一旦您添加的下一个数字变得足够小,那么它几乎不会使结果更准确.假设当下一个数字小于0.00001时,就该停止尝试改进结果了.
所以你将停在1 /(n*n)= 0.00001 => n*n = 100000 => n = sqrt(100000)=> n~ = 316
你的表达说停在10 ^(5 + 2)= 10,000,000
你可以告诉你是这样了,完全循环过于频繁,而不是提高结果的准确性与上次9999000次迭代.
是时候谈论真正的问题,太糟糕了,你没有解释你是如何得到如此严重错误的算法.但是你肯定在测试你的代码时发现它只是不太擅长计算pi的更精确的值.所以你想通过更频繁地迭代,你会得到更好的结果.
请注意,在此肘部测试中,您能够以足够的精度计算添加量也非常重要.我故意舍入数字,好像它是在能够执行5位精度的加法的机器上计算的.无论你做什么,结果都不会比5位更精确.
您在代码中使用double类型.由处理器直接支持,它没有无限的精度.您需要记住的唯一规则是使用double的计算永远不会比15位精确.同时记住浮动规则,它永远不会比7位数更精确.
所以,无论你通过什么价值presicion,结果可能永远不会超过15位更精确.这根本没用,你已经将pi的值精确到15位数.这是Math.Pi
解决这个问题需要做的一件事是使用精度高于double的类型.实际上,它需要是一种具有任意精度的类型,它至少需要与您传递的预定值一样准确.这种类型在.NET框架中不存在.找到一个可以为您提供一个库的库是SO的一个常见问题.