当前位置:   article > 正文

【基础】(C语言)高精度算法_c语言高精度计算

c语言高精度计算


前言:为什么我们需要高精度算法?

多数时候我们需要进行非常庞大的数字运算,其中涉及四则运算,加减乘除,但是当连最大的long long类型也容纳不下如此大的数字的时候,我们应该怎么办?
那么,我们就要用到今天所介绍的高精度算法,顾名思义,我们可以用一些特殊的方式来得出我们想要计算的答案。

一、高精度算法基础

在讲高精度算法之前,我们需要引入数组和字符串这两位我们在学习过程中的老朋友。
第一:我们知道,数组的优点是可以储存大量数字,并且每一位都是数的形式,运算时非常方便,但是数组在输入的时候必须要有分隔符,不符合数字的输入习惯。
第二:我们知道,字符串在输入的时候是连续的,不需要分隔符,非常符合数字的输入习惯,但是不能直接进行运算,非常不方便。
所以,我们可以就其两者取长补短,用数组来进行运算和储存数据,用字符串来输入数据!

二、高精度乘法

1.计算流程

  1. 通过字符串引入两串数字分别存放到两个字符数组
  2. 将其每一位数字逆序分别存放到两个整型数组
  3. 进行计算并处理进位(关键)
  4. 将结果存放到第三个整型数组当中(引进动态数组)
  5. 输出结果

第一:我们引进两串数字

char num1[102];
char num2[102];
scanf("%s", num1);
scanf("%s", num2);
  • 1
  • 2
  • 3
  • 4

第二:将每一位数字逆序存放整型数组

	int la,lb,lc;
    int a[2001]={0};
    int b[2001]={0};
    int c[2001]={0};//这是待会儿要存答案的数组
    la=strlen(num1);//取第一个字符串的长度
    lb=strlen(num2);//取第二个字符串的长度
    for(int i=0;i<la;i++)
    {//这里我们用la-i-1来实现逆序存放,将num数组的逆序存放在数组a中:即数字的个位存放在a【0】以此类推
        a[la-i-1]=num1[i]-'0';//通过ASCII码的运算,将字符数字转成整型数字
    }
    for(int i=0;i<lb;i++)
    {
        b[lb-i-1]=num2[i]-'0';
    }
    lc=la+lb;//记录两个字符串的总长度
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

第三:进行计算并处理进位

for(int i=0;i<la;i++)
    {
        for(int j=0;j<lb;j++)
        {
            c[i+j]+=a[i]*b[j];
            c[i+j+1]+=c[i+j]/10;
            c[i+j]%=10;
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

想必大家不知道这算法公式是怎样推导出来的吧,那就让我针对推导过程进行讲解吧!
在这里插入图片描述
在这里插入图片描述
第四:将结果存放到第三个整型数组当中(引进动态数组)

while(c[lc]==0&&lc>0)lc--;
    char *re=(char *)malloc(sizeof(char)*(lc+2));
    for(int i=lc;i>=0;i--){
        re[lc-i]=c[i]+'0';
    }
    re[lc+1]=0;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

4.1
没错,这里又出现了一个特别的while语句
while(c[lc]==0&&lc>0)lc–
它的作用是:比较大众的说法是删去前导零,不过这里有个小插曲,就是笔者在阅读其他作者的文章的时候并不能理解前导零是怎么产生的(没错就是这么傻 ),所以在这里我有另一种较为容易理解的说法。
还记得我们前面定义了两个字符串的长度和lc吗?
想想我们有两种情况:
1.在最高位有进位,那么这是存答案的数组就会往前再储存一位数字,存在c【lc】中(想想为什么)
2.在最高位没有进位,那么我们在初始化的时候就已经把c【lc】置为0了,那么我们就要将总长度lc(总位数)减掉,避免输出的时候在答案前面多了个0
4.2
这里我们引入动态数组的原因是笔者是用函数写的这部分运算,因此在函数结束时,函数会销毁,导致我们不能正常输出结果,因此需要另外开一个动态数组来存放我们的结果。
4.3:
有没有注意到 re[lc+1]=0,它可是至关重要的一步
笔者因为漏了它导致作业一直没能满分,因为内存的问题QAQ
它能够让我们在输出结果的时候及时地终止程序的读取,为什么呢?因为字符串在输出的时候只有读取到’\0’的时候才会终止,那么我们加上这句之后就是要让它在答案结尾处就终止输出,能避免不断输出而引起的内存出错哦!

第五:输出
没啥好讲的其实hhhhh

2.完整代码

代码如下:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char* multiply(char* num1, char* num2)
{
    int la,lb,lc;
    int a[2001]={0};
    int b[2001]={0};
    int c[2001]={0};
    la=strlen(num1);
    lb=strlen(num2);
    for(int i=0;i<la;i++)
    {
        a[la-i-1]=num1[i]-'0';
    }
    for(int i=0;i<lb;i++)
    {
        b[lb-i-1]=num2[i]-'0';
    }
    lc=la+lb;
    for(int i=0;i<la;i++)
    {
        for(int j=0;j<lb;j++)
        {
            c[i+j]+=a[i]*b[j];
            c[i+j+1]+=c[i+j]/10;
            c[i+j]%=10;
        }
    }
    while(c[lc]==0&&lc>0)lc--;
    char *re=(char *)malloc(sizeof(char)*(lc+2));
    for(int i=lc;i>=0;i--){
        re[lc-i]=c[i]+'0';
    }
    re[lc+1]=0;
    return re;
}
int main(){
	char num1[102];
    char num2[102];
    scanf("%s", num1);
    scanf("%s", num2);
    char* num = multiply(num1, num2);
    printf("%s", num);
    free(num);
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47

三、总结

希望这篇文章能够帮助到所有正在学习程序设计的朋友们,如果对这篇文章有任何问题的欢迎在评论区留言,笔者会一一回复的,也恳请大家多多提出建议,让我们的博客越来越好。
如果觉得这篇文章不错的话,不要忘记点个赞哦!

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号