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