计算第N个Pi数字

时间:2015-05-31 15:30:42

标签: c# algorithm pi digit

我试图计算Pi的第n位而不使用可以指定为参数的 static int CalculatePi(int pos) { List<int> result = new List<int>(); int digits = 102; int[] x = new int[digits * 3 + 2]; int[] r = new int[digits * 3 + 2]; for (int j = 0; j < x.Length; j++) x[j] = 20; for (int i = 0; i < digits; i++) { int carry = 0; for (int j = 0; j < x.Length; j++) { int num = (int)(x.Length - j - 1); int dem = num * 2 + 1; x[j] += carry; int q = x[j] / dem; r[j] = x[j] % dem; carry = q * num; } if (i < digits - 1) result.Add((int)(x[x.Length - 1] / 10)); r[x.Length - 1] = x[x.Length - 1] % 10; ; for (int j = 0; j < x.Length; j++) x[j] = r[j] * 10; } return result[pos]; } 。 我修改了一个现有的算法,因为我喜欢在不使用字符串转换或默认类的情况下找到第N个数字。 这就是我的算法目前的样子:

  static void Main(string[] args)
    {
        for (int i = 0; i < 100; i++)
        {
            Console.WriteLine("{0} digit of Pi is : {1}", i, CalculatePi(i));
        }

        Console.ReadKey();
    }

到目前为止,它一直工作到数字32,然后发生错误。 当我尝试打印这样的数字时:

<ul style="list-style-type:none; display:inline;">

对于第32位和第85位以及其他一些数字我得到10,这显然是不正确的。

enter image description here

27的原始数字如下:

... 3279502884 ...

但我得到

... 32794102884 ...

算法有什么问题,我该如何解决这个问题? 算法是否仍然可以调整以提高速度?

1 个答案:

答案 0 :(得分:5)

  

到目前为止,它一直有效,直到光标到达数字32.然后,抛出异常。

规则如下:

  • 数字31 is incorrect,因为它应该是5而不是4。
  • 数字32应为0.
  • 当你得到一个10位数的结果时,你需要将1翻到前一位,将10改为0。

当362 = 10时,下面的代码更改最多可达〜数字361。

一旦程序进入900,那么有很多错误的数字。

在你的循环中你可以通过跟踪前一个数字来做到这一点,只有在计算了后续数字之后才将它添加到列表中。

溢出需要在发生时进行处理,如下所示:

    int prev = 0;

    for (int i = 0; i < digits; i++)
    {
        int carry = 0;

        for (int j = 0; j < x.Length; j++)
        {
            int num = (int)(x.Length - j - 1);

            int dem = num * 2 + 1;

            x[j] += carry;

            int q = x[j] / dem;

            r[j] = x[j] % dem;

            carry = q * num;

        }

        // calculate the digit, but don't add to the list right away:
        int digit = (int)(x[x.Length - 1] / 10);

        // handle overflow:
        if(digit >= 10)
        {
            digit -= 10;

            prev++;

        }

        if (i > 0)
            result.Add(prev);

        // Store the digit for next time, when it will be the prev value:

        prev = digit;

        r[x.Length - 1] = x[x.Length - 1] % 10;

        for (int j = 0; j < x.Length; j++)
            x[j] = r[j] * 10;

    }

由于数字是逐个顺序更新的,比以前更早一次迭代,因此可以删除if (i < digits - 1)检查。

但是,您需要添加一个新的替换它:if (i > 0),因为您在循环的第一次传递中没有有效的prev值。

仅计算前100位数字的快乐巧合意味着上述功能将起作用。

然而,当一个10位数的结果跟随一个9位数的结果时,你认为会发生什么?不好消息我害怕,因为1需要携带到9(之前的值),这将使它成为10.

更强大的解决方案是完成您的计算,然后在列表中向后循环,将您遇到的任何10个数据传输到前一个数字,并传播任何进位。

请考虑以下事项:

for (int pos = digits - 2; pos >= 1; pos--)
{
     if(result[pos] >= 10)
     {
          result[pos] -= 10;

          result[pos - 1] += 1;

     }

}