一、使用线性表突破程序设计语言内置变量的数值和有效数字范围的限制,为了实现高精度圆周率的计算,先根据数学公式进行对PI高精度运算,如图1-1。根据这个数学公式 π2 = 0nn!2n+1‼ 即 Rn+1=Rn*n2n+1,R1=1,sum= π=2* n=1∞Rn 来计算PI值。首先先建立双链表,再对其初始化。根据其特性,实现了对大数的加法,乘法和除法,以此来完成对PI的高精度计算如图1-1,最后将PI的值储存到文件中如图1-2。
#include <stdio.h>
#include <stdlib.h>// 定义双链表节点结构体
typedef struct list
{int data; // 节点数据域struct list *next; // 指向下一个节点的指针struct list *pre; // 指向前一个节点的指针
}list;// 初始化双链表,返回链表头节点
list* Initlist()
{list *head;head = (list*)malloc(sizeof(list)); // 为头节点分配内存if (!head)exit(EXIT_FAILURE); // 如果内存分配失败,则退出程序elsehead->next = head->pre = head; // 初始化头节点的next和pre指针指向自己return head;
}// 创建指定长度的双链表,返回链表头节点
list *Creatlist(list *head)
{list *p = head;for (int i = 0; i < 1000; i++) // 循环创建1000个节点{list *q = (list*)malloc(sizeof(list));if (!q)exit(EXIT_FAILURE); // 如果内存分配失败,则退出程序else{q->data = 0; // 将新节点q的数据域设置为0q->pre = p; // 将新节点q的前置指针指向当前节点pp->next = q; // 将当前节点p的下一个节点指针指向新节点qq->next = head; // 将新节点q的下一个节点指针指向链表的头节点head,形成一个环形链表head->pre = q; // 将头节点head的前置指针指向新节点q,完成环形链表的构建p = p->next; // 将当前节点p移动到下一个节点,为下一次循环做准备}}return head;
}void Save(int n) //存储PI
{FILE *fp = fopen("E:\\C语言的软件\\数据结构与算法\\1\\PI的存储.txt","w+");fprintf(fp,"%d",n);fclose(fp);
}int main()
{int n;printf("请输入PI要精确到的位数\n");scanf("%d", &n); // 输入需要的小数位数list *number, *sum;list *p, *q, *x;number = Initlist(); // 初始化number链表sum = Initlist(); // 初始化sum链表number = Creatlist(number); // 创建number链表sum = Creatlist(sum); // 创建sum链表number->next->data = 2; // number链表的第二位储存2,即2*R(1)=2sum->next->data = 2; // sum链表的第二位也储存2int a = 0, b = 0; // 分别是用来暂时存储进位和余数for (int i = 1; i < 2000; i++) // 循环两千次,用于计算π的近似值{p = number->pre; // 开始大数乘法时从number链表的尾部开始while (p != number) //大于10则把10位的数字给b,个位数字放入data域中。{ //乘法运算a = p->data * i + b; // 计算当前位乘以i加上之前的进位p->data = a % 10; // 取个位数放入当前节点的data域b = a / 10; // 计算进位p = p->pre; // 移动到前一个节点}b = 0; // 清空b,为除法做准备p = number->next; // 开始大数除法时从number链表的前部开始while (p != number) //若计算出的数字为自然数,则直接放入data域;若等于0,或为小数,则要计算余数并给b。{ //除法运算a = p->data + b * 10; // 计算当前位加上之前的余数乘以10p->data = a / (2 * i + 1); // 计算当前位的商,并放入当前节点的data域b = a % (2 * i + 1); // 计算余数p = p->next; // 移动到下一个节点}b = 0; // 清零bp = number->pre; // 开始大数加法时从number链表的尾部开始q = sum->pre; // 从sum链表的尾部开始while (p != number) //大于10进位,并储存个位数,进位数字赋给b。{ // 加法计算a = p->data + q->data + b; // 计算当前位的和加上之前的进位q->data = a % 10; // 取个位数放入sum链表的当前节点的data域b = a / 10; // 计算进位p = p->pre; // 移动到number链表的前一个节点q = q->pre; // 移动到sum链表的前一个节点}}printf("3."); // 输出π的前缀"3."x = sum->next->next; // 从sum链表的第三个节点开始输出,即输出π的小数部分FILE *fp = fopen("E:\\C语言的软件\\数据结构与算法\\1\\PI的存储.txt","w+");fprintf(fp,"3.");for (int i = 0; i < n; i++) // 输出n位小数{fprintf(fp,"%d",x->data); //存储PIprintf("%d", x->data); // 输出当前节点的data域的值x = x->next; // 移动到下一个节点}fclose(fp);return 0;
}