详解高精度乘法/加法

完整代码在最后!!!

之前把加法忘记了,现在补充在了最后

高精度乘法
使用条件:特别大的两个数字相乘(long long 无法满足)
具体步骤

第一步:
用字符串的形式读入需要相乘的两个数(如果用作函数需要自行转换为字符串形式)

    cin >> ch1 >> ch2 ;
    //读入两个相乘的数的字符串
    int len1=strlen(ch1),len2=strlen(ch2);
    //记录他们各自的位数

第二步:
将字符串形式的两个数存入两个数组中
如何理解?
例如我们有字符串“123”,我们就定义数组a为a[0]=3,a[1]=2,a[3]=1;(为什么是倒着的?别急,慢慢讲)

    for(i=0;i<len1;i++)
    {
        a[len1-i-1]=ch1[i]-48;
        //减48是为了将字符变为数字,(数字1的代码为49)
    }
    for(i=0;i<len2;i++)
    {
        b[len2-i-1]=ch2[i]-48;//倒着定义?没错!
    }

所以为什么要倒着定义呢?
这其实是为了我们更好的计算
如果输入的字符串为“100”,那ch1[0]=‘1’,ch1[1]=‘0’,ch1[2]=‘0’,如果不倒着定义,我们的a[0]=1,a[1]=0,a[2]=0,但后面的也都是0呀!那么这个100和1000,10000有什么区别呢,就还必须用位数去研限制,特别麻烦,所以如果倒过来变成001就不用再用位数去限制0。

第三步:
结果预处理
我们知道,两个数相乘时会将一个数中的每一个数与另一个数的每一个数相乘,再经过一些错位相加而得到我们的结果,这里也是一个原理,理解了这样也就掌握了高精度相乘的精髓。
值得一提的是,上面提到的一些错位是怎么错发呢,随便一个草稿就能发现,其实最后每个相加的数直接都有一定的关系,那就是他们是在两个数中位置序号(从右边数起)的和相同的两个数相乘而得到的乘积,举个例123*乘45678,将前数的位置序号写在前,那么3和8相乘就是1、1,他们的和是2,其他还有两个数序号和为2的吗,显然没有,所以你会发现在相乘最后相加时,他们的乘积(大于10时要mod10)下面没有其他数的乘积,而2和4他们的序号为2、5,和为7,所以他们的乘积会和序号为3,4(和为7)的1、5的乘积相加。

for(i=0;i<len1;i++)
    {
        int j;
        for(j=0;j<len2;j++)
        {
            c[i+j]+=a[i]*b[j];
            //此处先不考虑进位问题
        }
    }

第四步:
结果的处理
谈谈下面的这个m是什么
一个位数为a的数和一个位数为b的数相乘
他们的结果只可能是(a+b-1)位或(a+b)位
如2X3=6
如5X4=20
所以我们的这两个数相乘,最多可能有(len1+len2)位数字,而我们的数组是从角标位0的开始使用的,所以(len1+len2)位数字只会用到(len1+len2-1)的角标,此处的m就是记录角标可能的最大位置(如果这里没有数字就会是0)

int m=len1+len2-1;
    for(i=0;i<m;i++)
    /*虽然可能有角标位m的数字存在,
    但那是前一位会进位,如果进了位
    下面的判断语句里位自动位角标位m的空间里加上进的位数
    所以不用循环到终点m*/
    {
        if(c[i]>10)
        {
            c[i+1]+=c[i]/10;//进位运算,进的位加上之前有的数字
            c[i]%=10;
        }
    }
    while(c[m]==0&&m>=1)
    /*此处位验证结果最后一位的角标是否位m,
    如果不是m,c[m]就会是0,
    因为 c[m-1]/10=0,c[m]就不会加上任何东西
    注意的是,防止结果就是0的情况,
    所以角标比1还小(位0)就不再减了*/
    {
        m--;
    }

第五步:
输出结果

    for(i=m;i>=0;i--)
    {
        cout << c[i];//注意输出的顺序哦,倒过来输出。
    }
    cout << endl ;

完整代码

#include  <bits/stdc++.h>

using namespace std;
int a[40005],b[40005],c[40005];
char ch1[40005],ch2[40005];
int main()
{
    cin >> ch1 >> ch2 ;
    int len1=strlen(ch1),len2=strlen(ch2);
    int i;
    for(i=0;i<len1;i++)
    {
        a[len1-i-1]=ch1[i]-48;
    }
    for(i=0;i<len2;i++)
    {
        b[len2-i-1]=ch2[i]-48;
    }
    for(i=0;i<len1;i++)
    {
        int j;
        for(j=0;j<len2;j++)
        {
            c[i+j]+=a[i]*b[j];
        }
    }
    int m=len1+len2-1;
    for(i=0;i<m;i++)
    {
        if(c[i]>10)
        {
            c[i+1]+=c[i]/10;
            c[i]%=10;
        }
    }
    while(c[m]==0&&m>=1)
    {
        m--;
    }
    for(i=m;i>=0;i--)
    {
        cout << c[i];
    }
    cout << endl ;
    return 0;
}

高精度加法

#include <bits/stdc++.h>

using namespace std;
int a[1000],b[1000],ans[2000];
char ch1[1000],ch2[1000];
int main()
{
    cin >> ch1 >> ch2;
    int len1=strlen(ch1),len2=strlen(ch2);
    for(int i=0;i<len1;i++)
    {
        a[len1-1-i]=ch1[i]-48;
    }
    for(int i=0;i<len2;i++)
    {
        b[len2-1-i]=ch2[i]-48;
    }
    int m=len1>len2?len1:len2;
    for(int i=0;i<m;i++)
    {
        ans[i]+=(a[i]+b[i]);
        ans[i+1]+=(ans[i])/10;
    }
    while(ans[m]==0&&m>=1)
        m--;
    for(int i=m;i>=0;i--)
    {
        cout << ans[i];
    }
    cout << endl ;
    return 0;
}

发布了44 篇原创文章 · 获赞 13 · 访问量 2353

猜你喜欢

转载自blog.csdn.net/NEFU_kadia/article/details/104097495