指定继续计算 Pi 的起始索引
Specify a starting index for continuation of calculating Pi
此 C# 代码将计算 Pi 到我指定的任何长度。我希望能够从给定的索引开始,而无需重新计算到那个点。精度不是一个大问题,因为这是一个拼图项目,但我确实需要这段代码来一遍又一遍地重现相同的结果。它按原样运行良好,但我一直无法弄清楚如何修改起点。
//Looking to pass BigInteger to specify a starting index for continuation of calculating Pi
public static BigInteger GetPi(int digits, int iterations)
{
return 16 * ArcTan1OverX(5, digits).ElementAt(iterations)
- 4 * ArcTan1OverX(239, digits).ElementAt(iterations);
}
public static IEnumerable<BigInteger> ArcTan1OverX(int x, int digits)
{
var mag = BigInteger.Pow(10, digits);
var sum = BigInteger.Zero;
bool sign = true;
for (int i = 1; true; i += 2)
{
var cur = mag / (BigInteger.Pow(x, i) * i);
if (sign)
{
sum += cur;
}
else
{
sum -= cur;
}
yield return sum;
sign = !sign;
}
}
您正在使用 Machin formula with the Taylor serie expansion for Arctan. It should give you about 1.4 digits of precision for each "cycle" (see here)。你不能“捷径”计算泰勒级数。您可以稍微加快程序速度,删除 IEnumerable<BigInteger>
部分并简单地返回第 n 次迭代(yield
指令有成本)并通过使用固定乘法更改 BigInteger.Pow
。但计算仍将迭代进行。没有已知的方法可以在 O(1) 时间内计算精度为 n 位的 PI。
请注意,有些算法(请参阅 wiki)在较少的循环次数中收敛,但我不确定它们是否在较少的操作次数中收敛(它们的循环要复杂得多).
代码的优化版本:
public static BigInteger GetPi2(int digits, int iterations)
{
return 16 * ArcTan1OverX2(5, digits, iterations)
- 4 * ArcTan1OverX2(239, digits, iterations);
}
public static BigInteger ArcTan1OverX2(int x, int digits, int iterations)
{
var mag = BigInteger.Pow(10, digits);
var sum = BigInteger.Zero;
bool sign = true;
int imax = 1 + (2 * iterations);
int xsquared = x * x;
BigInteger pow = x;
for (int i = 1; i <= imax; i += 2)
{
if (i != 1)
{
pow *= xsquared;
}
var cur = mag / (pow * i);
if (sign)
{
sum += cur;
}
else
{
sum -= cur;
}
sign = !sign;
}
return sum;
}
此 C# 代码将计算 Pi 到我指定的任何长度。我希望能够从给定的索引开始,而无需重新计算到那个点。精度不是一个大问题,因为这是一个拼图项目,但我确实需要这段代码来一遍又一遍地重现相同的结果。它按原样运行良好,但我一直无法弄清楚如何修改起点。
//Looking to pass BigInteger to specify a starting index for continuation of calculating Pi
public static BigInteger GetPi(int digits, int iterations)
{
return 16 * ArcTan1OverX(5, digits).ElementAt(iterations)
- 4 * ArcTan1OverX(239, digits).ElementAt(iterations);
}
public static IEnumerable<BigInteger> ArcTan1OverX(int x, int digits)
{
var mag = BigInteger.Pow(10, digits);
var sum = BigInteger.Zero;
bool sign = true;
for (int i = 1; true; i += 2)
{
var cur = mag / (BigInteger.Pow(x, i) * i);
if (sign)
{
sum += cur;
}
else
{
sum -= cur;
}
yield return sum;
sign = !sign;
}
}
您正在使用 Machin formula with the Taylor serie expansion for Arctan. It should give you about 1.4 digits of precision for each "cycle" (see here)。你不能“捷径”计算泰勒级数。您可以稍微加快程序速度,删除 IEnumerable<BigInteger>
部分并简单地返回第 n 次迭代(yield
指令有成本)并通过使用固定乘法更改 BigInteger.Pow
。但计算仍将迭代进行。没有已知的方法可以在 O(1) 时间内计算精度为 n 位的 PI。
请注意,有些算法(请参阅 wiki)在较少的循环次数中收敛,但我不确定它们是否在较少的操作次数中收敛(它们的循环要复杂得多).
代码的优化版本:
public static BigInteger GetPi2(int digits, int iterations)
{
return 16 * ArcTan1OverX2(5, digits, iterations)
- 4 * ArcTan1OverX2(239, digits, iterations);
}
public static BigInteger ArcTan1OverX2(int x, int digits, int iterations)
{
var mag = BigInteger.Pow(10, digits);
var sum = BigInteger.Zero;
bool sign = true;
int imax = 1 + (2 * iterations);
int xsquared = x * x;
BigInteger pow = x;
for (int i = 1; i <= imax; i += 2)
{
if (i != 1)
{
pow *= xsquared;
}
var cur = mag / (pow * i);
if (sign)
{
sum += cur;
}
else
{
sum -= cur;
}
sign = !sign;
}
return sum;
}