高精度计算pi值——参考后

高精度计算pi值(参考后)

问题

问题如图,高精度计算pi值用泰勒展开式计算。
在这里插入图片描述

参考

参考了大佬的代码后加了原理以及注释;大佬原文
https://blog.csdn.net/zhao2018/article/details/79929881?utm_source=app&app_version=4.6.0

原理

1.由于计算的精度会达到很多位数,而浮点型数据最多位数32或64位,无法满足需求,则只能考虑自己建立一个元素组来计算,其中有整数部分,还有很多位数的小数部分。暂时考虑用链表计算,每个节点存储一位数的值。
2.计算时观察泰勒展开式发现表达式是将n个具有递推关系的式子Rn相加,而Rn与Rn-1关系式中有乘法除法,则考虑设计加法,乘法,除法函数。
3.由于多位数计算加法和乘法需从最低位开始计算,而单向链表定位最低位比较困难,则考虑双向循环链表,可使p-pre从而指向最后一个结点—表示最低位的数的值
4.分别写出各运算的算法—需考虑进位,补数等竖式计算原则
5.循环内进行运算,运算结束后根据n的值来输出链表的前面多少个结点,从而得到最终pi的值。

代码

代码以及相关注释如下:

#include <stdio.h>  
#include <stdlib.h>  
#define MAX 1000  
typedef struct Node
{
    int data;//每个结点一个data,代表每个位数上的值
    struct Node* pre;
    struct Node* next;
} LNode, * LinkList;
void Create(LinkList L);
void Sum(LinkList a, LinkList b);
void Multiply(LinkList a, int k);
void Divide(LinkList a, int k);
int main()
{
    int n, i, top, bottom, s = 1;
    printf("请输入n值(即精确到小数点后多少位)");
    scanf_s("%d", &n);
    LinkList sum, R;
    sum = (LinkList)malloc(sizeof(LNode));
    R = (LinkList)malloc(sizeof(LNode));
    Create(sum);
    Create(R);
    sum->next->data = 3;//之所以取3是因为pi是6分之pi的6倍,而R1同理也应该乘以6,才能求出pi而不是6分之pi
    R->next->data = 3;
    while (s < 2000)
    {
        top = (2 * s - 1) * (2 * s - 1);//top是Rn与Rn-1关系式当中的分子
        bottom = 8 * s * (2 * s + 1);//bottom是Rn与Rn-1关系式当中的分母
        Multiply(R, top);//每一位与top相乘
        Divide(R, bottom);//每一位与top相除
        Sum(R, sum);//将Rn与Rn-1相加
        s++;
    }//计算1999个式子相加后得到的值即为
    if (n == 0)
    {
        printf("3\n");
    }//精度取整
    else
    {
        sum = sum->next;
        printf("%d.", sum->data);//整数部分后加小数点
        for (i = 0; i < n; i++)
        {
            printf("%d", sum->next->data);
            sum = sum->next;
        }//实际上以及计算出sum链表的每一位,这里n为多少,输出多少为小数点后的即取多少位精确值
    }
    printf("\n");
    return 0;
}
void Create(LinkList L)
{
    LinkList p = L, q;
    int i;
    L->next = L->pre = L;
    for (i = 0; i < MAX; i++)
    {
        q = (LinkList)malloc(sizeof(LNode));
        q->data = 0;
        p->next = q;
        q->pre = p;
        q->next = L;
        L->pre = q;
        p = q;
    }//MAX在这里确定了最终链表是1000个元素
}//建立了一个双向循环链表,里面的结点元素全部为0-》循环链表可以使之第一次就pre从而指向尾部-》位数最小的那位-》符合多位数的运算
void Sum(LinkList a, LinkList b)
{
    LinkList p = a->pre, q = b->pre;
    int n;
    while (q != b)
    {
        n = q->data + p->data;//低位相加
        q->data = n % 10;//取余得低位的结果
        q->pre->data += n / 10;//高位进位
        q = q->pre;
        p = p->pre;
    }//从最低位开始加起直到走完一个循环
}//每一位数都相加,考虑进位
void Multiply(LinkList a, int n)
{
    LinkList p = a->pre;
    int x, y = 0;
    for (; p != a; p = p->pre)
    {
        x = (p->data) * n + y;//y是比该位低的那一位做乘法运算时多出来的需要加到高位的,初始化时为0
        y = x / 10;//作为下一次加到高位的数
        p->data = x % 10;//本位的结果
    }
    x = (p->data) * n + y;
    y = x / 10;
    p->data = x % 10;
}//每一位从低位到高位依次与top相乘
void Divide(LinkList a, int n)
{
    LinkList p = a->next;
    int x, y = 0;
    for (; p != a; p = p->next)
    {
        x = p->data + y * 10;//上一位到这一位补充的y乘以10,y初始化时为0
        p->data = x / n;//本位结果
        y = x % n;//除法得到的余数进入比本位低的那位乘以10加上去
    }
}//每一位从高位到低位依次与bottom相除

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值