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