In-depth interpretation of the program for finding π

In-depth interpretation of the program for finding π

The principle of the method used in this article can be used in the calculation of irrational numbers generated by series or Taylor formula

Source code display

#include<stdio.h>
#include<math.h>
#include<malloc.h>
int main()
{
    
    
    double s;
    int b,x,n,c,i,j,d,l;
    printf("请输入精确位数:");
    scanf("%d",&x);
   //x应为8位数及以下,理论上小数点后一亿位时,内存分配约3个多G;n亦在有效范围内

    short int *a=(short int*)malloc(sizeof(short int)*(6+x));
     for(s=0,n=1;;n++)//累加确定项数.
     {
    
    
       s=s+log10((2*n+1)/n);
       if(s>x+1)
        break;
     }
     for(i=0;i<=x+5;i++)//初始化前x+5个元素为0;
       a[i]=0;
     for(c=1,j=n;j>=1;j--)//按公式分布计算。
     {
    
    
       d=2*j+1;
       for(i=0;i<=x+4;i++)//各位实施除2j+1.
       {
    
    
        a[i]=c/d;         //
        c=(c%d)*10+a[i+1];//模仿手工除法求商
       }
       a[x+5]=c/d;
       for(b=0,i=x+5;i>=0;i--)//各位实施乘j
       {
    
    
        a[i]=a[i]*j+b;//
        b=a[i]/10;    //
        a[i]=a[i]%10;//模仿手工乘法进位
       }
       a[0]=a[0]+1;//整数加1,即公式中的1+n/(2n+1)中的1;
       c=a[0];//下次循环中的起始c是上次计算得到的1+n/(2n+1)的整数部分
     }
     for(b=0,i=x+5;i>=0;i--)//按公式各位乘2
     {
    
    
       a[i]=a[i]*2+b;
       b=a[i]/10;
       a[i]=a[i]%10;
     }
     printf("\n%d----PI=%d.",x,a[0]);
     for(l=10,i=1;i<=x;i++)
     {
    
    
       printf("%d",a[i]);
       l++;
       if(l%10==0)
        putchar(' ');
       if(l%50==0)
        putchar('\n');
     }
     putchar('\n');
     free(a);
return 0;
//这个程序将π 的每一位数放进一个数组元素中,a[0]是整数位,a[ i ]分别对应小数点后 i 位

Line-by-line analysis

  • Needless to say, rows 6, 7, 8

Define the variables to be used in the program, the specific purpose will be understood one by one during the explanation process, just follow my thoughts.
Line 9 requires the input of the exact number of digits required, which is stored as x. In this explanation, we take x = 5, which requires 5 digits after the decimal point of π as an example.

  • Line 12:
int *a=(int*)malloc(sizeof(int)*(6+x));

The memory space of x+6=11 elements is dynamically allocated. Why do we need 11 elements? Don't we only require 5 digits after the decimal point plus the integer part for a total of 6 numbers?
This is to ensure the accuracy of the solution process, and the error cannot be amplified step by step in the calculation process due to insufficient number of digits. The fractional part has only 5 digits. I use 6 elements to store each digit of π, and the remaining 5 elements are the part I want to ensure its accuracy. As you can see, the integer part is output on line 45 and line 46. When looping the output, I only output the fractional part a[ 1] to a[ x] totaling x, that is, the last x digits of π, and the rest is discarded.

  • Loop in lines 13-18
 for(s=0,n=1;;n++)//累加确定项数.
{
    
    
    s=s+log10((2*n+1)/n);
    if(s>x+1)
    break;
}

Why use this loop? Let's start with the formula. I will simplify this formula once:

I want to ensure that when n is equal to a certain value, its influence on π can be ignored. In this example, the last 5 digits of π are required, that is, I want to
control the influence of n to 6 digits after the decimal point, that is,
a [n] <0.000001 = 1 0 − 6 = 1 0 − (x + 1) a[n] <0.000001=10^{-6}=10^{-(x+1)}a[n]<0.000001=106=10- ( X + . 1 )

programlog 10 () log_ {10}log10( ) Islg () lg()After l g ( ) is calculated, we get the n in the calculation formula. The formula is an infinite series, which of course cannot be counted as an infinite number.
From this step, the sum of the first n terms in the calculation formula can meet the accuracy requirements.

  • Lines 19-20:

Initialize all array elements to 0.

for(i=0;i<=x+5;i++)//初始化前x+5个元素为0;
    a[i]=0;
  • Lines 21~38:
    This is the core of this program, let’s take it step by step
for(c=1,j=n;j>=1;j--)//按公式分布计算。
{
    
    
    d=2*j+1;
    for(i=0;i<=x+4;i++)//各位实施除2j+1.
    {
    
    
        a[i]=c/d;         //
        c=(c%d)*10+a[i+1];//模仿手工除法求商
    }
    a[x+5]=c/d;
    for(b=0,i=x+5;i>=0;i--)//各位实施乘j
    {
    
    
        a[i]=a[i]*j+b;//
        b=a[i]/10;    //
        a[i]=a[i]%10;//模仿手工乘法进位
    }
    a[0]=a[0]+1;//整数加1,即公式中的1+n/(2n+1)中的1;
    c=a[0];//下次循环中的起始c是上次计算得到的1+n/(2n+1)的整数部分
}

The simulation runs once, the first large loop c =1, j=n
to the inner layer: d = 2 j +1 = 2 n +1.
Then the first for loop in the inner layer:

 for(i=0;i<=x+4;i++)//各位实施除2j+1.
{
    
    
    a[i]=c/d;         //
    c=(c%d)*10+a[i+1];//模仿手工除法求商
}

Here involves high-precision division . I will talk about the function of this loop on the paper: the

loop will put one bit of the quotient obtained each time into the array. c is used to temporarily store the remainder of each time. As for why +a[ i+1] appears,
it is related to the next big cycle, which will be demonstrated in a table later. Let's first look at the running process of this small loop that does division:

  • The first time: a [0] = 1/41 = 0; c=1%41*10+0=10;
  • The second time: a [1] = 10/41 = 0; c = 10%41*10+0 = 100;
  • The third time: a [2] = 100/41=2; c = 100%41 *10+0=180;
  • The fourth time: a [3] = 180/41=4; c = 180%41 *10+0 =160;
    -...
  • The x+5th time is the 10th time: a [9] = 3;

Why does this loop only execute x+5 times? Doesn’t it require x+6 elements? As you can see, there is a modification to c in the loop. When we
find the last quotient we need , we do n’t need the remainder anymore, so find the x+6 quotient that is a [x+5] = For a [10], c is not modified and calculated separately outside the loop.
At this time, the array saves the value of 1/41 accurate to the last 10 digits: 1/41 = 0.0243902439 1/41 = 0.02439024391/41=0.0243902439

Alt

  • Then the second for loop in the inner layer:
for(b=0,i=x+5;i>=0;i--)//各位实施乘j
{
    
    
    a[i]=a[i]*j+b;//
    b=a[i]/10;    //
    a[i]=a[i]%10;//模仿手工乘法进位
}

This loop simulates a high-precision multiplication operation, and b retains each carry. I just calculated 1/41, and the formula is n/(2n+1) that is
20/41 , so we need to multiply the 1/41 just calculated by 20; how to do the multiplication in the array?

Look at the figure below: In this way, we get the exact value of 20/41, which is 20*(1/41) = 0.4878048780;

then, why there is a [0] = a [0] + 1;
let’s look at the formula:

at this time the array Storage 1 + 20/41 = 1.4878048780 1+ 20/41 = 1.48780487801+20/41=. 1 . . 4 . 8 . 7 . 8 0 . 4 . 8 . 7 . 8 0 exact value.

Then, why should there be c=a[0]?
We see that c will do the calculation of the numerator of a[i]=c/d in the next cycle. why is it like this?
Let's look at the above formula. I have calculated the formula 1+ 20/41 at the innermost level of the brackets and put it in the array a. Let
a represent 1+ 20/41 at this time, which is 1.4878048780.
Then we need to calculate a/39 next time in the loop,
let’s try, 1.48 divided by 39 and 1 divided by 39 are different in computer calculations,
yes, they are the same because of the integer division. For example, 1.3/2=1/2=0, 5.3/2=5/2=2,
that is, the fractional part has no effect on this division operation, so we do not use the fractional part.

Transfer to the second cycle: j = n-1 = 39;
c is equal to 1 + 20/41, rounded to 1;
c/d at this time is equivalent to (1 + 20/41) / 39 that is a / 39 1 / 39;
do division again.
Let’s go back and see why it appears in line 27 of the program.

c=(c%d)*10+a[i+1]

Because this time the dividend is not 1, but 1+ 20/41 stored in the array.
We let c retain only the integer bits of a because the decimals are discarded in the calculation of c/d, but the original decimals in the array are still
the key to ensuring accuracy. We can look at the calculation process this time: after the

division is calculated, the multiplication is calculated, that is, 19/ 39* (1+ 20/41) is calculated, and then 1 is added after the calculation;
it is 1+ 19/ 39* (1+ 20 /41), and so on, thinking about it layer by layer. Finally, the array is stored and the

approximate exact value of π/2 is obtained.

  • Line 39~44 of the program:
    We got π/2, how to get π? Multiply by 2 is not over.
    The multiplication principle of these lines of program is the same as the multiplication in the loop mentioned earlier, except that the
    j in the loop is changed to 2 to multiply the value obtained by 2.

This is basically the end, the value of π is already in the array.

  • Line 45~55: Output the π value stored in the array, one line for every 50 numbers, and a space for every 10 numbers,
  • Lines 46~54 control the output of this format.
  • Line 56 releases the dynamically allocated array memory, a useless statement.

Guess you like

Origin blog.csdn.net/qq_37957939/article/details/106809598