高精度算法(加减乘除)

一、简介

在一般的科学计算中,会经常算到小数点后几百位或者更多,当然也可能是几千亿几百亿的大数字。一般这类数字我们统称为高精度数,高精度算法是用计算机对于超大数据的一种模拟加、减、乘、除、乘方、阶乘、开方等运算。 对于一个很大的数字N >= 10^ 100,很显然这样的数字无法在计算机中正常存储。于是, 我们想到了办法,将这个数字拆开,拆成一位一位的或者是四位四位的存储到一个数组中,用一个数组去表示一个数字。这样这个数字就被称谓是高精度数。 对于高精度数,也要像平常数一样做加减乘除以及乘方的运算,于是就有了高精度算法。

二、高精度加法

读小学时我们做加法都采用竖式方法,从小到大每位数逐位相加,大于10的进位。这里采用的就是这种方法。

#include <bits/stdc++.h>
using namespace std;

char at[105],bt[105];
int a[105],b[105],c[105];

int main()
{
    cin>>at;
    cin>>bt;
    //将数a从小位到大位逐个储存在数组a中
    for(int i=0;i<strlen(at);++i)
        a[i+1]=at[strlen(at)-i-1]-'0';
    int lena=strlen(at);

    //将数b从小位到大位逐个储存在数组b中
    for(int i=0;i<strlen(bt);++i)
        b[i+1]=bt[strlen(bt)-i-1]-'0';
    int lenb=strlen(bt);

    //a+b的结果储存在c数组中
    int lenc=1;
    int yu=0;
    while(lenc<=lena||lenc<=lenb)
    {
        //本位的计算结果为两数此位之和加上前面位数多出来的进位
        c[lenc]=a[lenc]+b[lenc]+yu;
        //多出来的进位
        yu=c[lenc]/10;
        c[lenc]%=10;
        lenc++;
    }
    c[lenc]=yu;   //最后可能还有进位
    if(c[lenc]==0)
        lenc--;

    for(int i=lenc;i>=1;--i)
        cout<<c[i];
    cout<<endl;
    return 0;
}

三、高精度减法

类似加法这里是竖式减法,从小到大逐位相减,不够的向前借1,但有一点要注意被减数要比减数大,否则交换两数位置,最后结果前输出一个负号。

#include <bits/stdc++.h>
using namespace std;

//a-b
char at[105],bt[105],tmp[105];
int a[105],b[105],c[105];

int main()
{
    cin>>at;
    cin>>bt;

    //如果a<b,输出负号,交换a和b的位置
    if(strlen(at)<strlen(bt)||(strlen(at)==strlen(bt)&&strcmp(at,bt)<0))
    {
        strcpy(tmp,at);
        strcpy(at,bt);
        strcpy(bt,tmp);
        cout<<"-";
    }

    //将数a从小位到大位逐个储存在数组a中
    for(int i=0;i<strlen(at);++i)
        a[i+1]=at[strlen(at)-i-1]-'0';
    int lena=strlen(at);

    //将数b从小位到大位逐个储存在数组b中
    for(int i=0;i<strlen(bt);++i)
        b[i+1]=bt[strlen(bt)-i-1]-'0';
    int lenb=strlen(bt);

    int lenc=1;
    while(lenc<=lena||lenc<=lenb)
    {
        //本位不够向上一位借一
        if(a[lenc]<b[lenc])
        {
            a[lenc]+=10;
            a[lenc+1]-=1;
        }
        c[lenc]=a[lenc]-b[lenc];
        lenc++;
    }

    //把前置所有为0的位舍去 但至少留一个0(a=b的情况)
    while(c[lenc]==0&&lenc>1)
        lenc--;
    for(int i=lenc;i>=1;--i)
        cout<<c[i];
    cout<<endl;

    return 0;
}

四、高精度乘法

类似加法,也可以用竖式求乘法。在做乘法运算时,同样也有进位,同时对每一位进行乘法运算时,必须进行错位相加。

每一位的计算c[i+j-1]+=a[i]*b[j]+yu

#include <bits/stdc++.h>
using namespace std;

char at[105],bt[105];
int a[105],b[105],c[210];

int main()
{
    cin>>at;
    cin>>bt;

    int lena=strlen(at);
    for(int i=0;i<lena;++i)
        a[i+1]=at[lena-i-1]-'0';
    
    int lenb=strlen(bt);
    for(int i=0;i<lenb;++i)
        b[i+1]=bt[lenb-i-1]-'0';

    int yu=0;
    for(int i=1;i<=lena;++i)
    {
        yu=0;
        //用a的i位逐个乘以b的每一位
        for(int j=1;j<=lenb;++j)
        {
            c[i+j-1]+=a[i]*b[j]+yu;  //加上上一位运算多出来的
            yu=c[i+j-1]/10;   //多出来的进位
            c[i+j-1]%=10;
        }
        c[i+lenb]+=yu;
    }

    int lenc=lena*lenb;
    while(c[lenc]==0&&lenc>1)  //删去前导0
        lenc--;
    for(int i=lenc;i>=1;--i)
        cout<<c[i];
    cout<<endl;

    return 0;
}

五、高精度除法

1、高精除以低精

高精除以低精,采用的是按位相除法,从大位到小位高精的每一位除以低精,不够的移到下一位运算。

#include <bits/stdc++.h>
using namespace std;

char at[105];
int a[105],b,c[105];

int main()
{
    cin>>at;
    cin>>b;

    //将数a从大位到小位逐个储存在数组a中
    int lena=strlen(at);
    for(int i=0;i<lena;++i)
        a[i+1]=at[i]-'0';
    
    int yu=0;
    for(int i=1;i<=lena;++i)
    {
        c[i]=(yu*10+a[i])/b;  //上一位剩下的乘10再加上本位
        yu=(yu*10+a[i])%b;  //取出本次运算剩下的
    }
    int lenc=1;
    while(c[lenc]==0&&lenc<lena)  //删去前导0
        lenc++;
    for(int i=lenc;i<=lena;++i)
        cout<<c[i];
    cout<<endl;
    return 0;
}

2、高精除以高精

高精除以高精是高精度算法中实现最复杂的,采用的是减法模拟除法,对被除数的每一位都减去除数

如989除以12,我们可以用989一次次减去12,但逐个相减效率太慢。我们可以直接用989-12*10,相当于减去10次了,也就相当于98-12。代码也是基于这个思想实现。

#include <bits/stdc++.h>
using namespace std;

char at[105],bt[105];
int a[105],b[105],c[105];

int compare(int a[],int b[])//比较a、b,若a>b为1;若a<b为-1;若a=b为0
{
    int i;
    if(a[0]>b[0])
        return 1;
    if(a[0]<b[0])
        return -1;
    for(i=a[0];i>0;i--)//从高位到低位比较
    {
        if(a[i]>b[i])
            return 1;
        if(a[i]<b[i])
            return -1;
    }
    return 0;
}
 
int main()
{
 
    cin>>at>>bt;
    a[0]=strlen(at);//a[0]存储串1的位数
    b[0]=strlen(bt);//b[0]存储串2的位数
    for(int i=1;i<=a[0];i++)
        a[i]=at[a[0]-i]-'0';
    for(int i=1;i<=b[0];i++)
        b[i]=bt[b[0]-i]-'0';
 
 
    int temp[105];
    c[0]=a[0]-b[0]+1;
    for(int i=c[0];i>0;i--)
    {
        memset(temp,0,sizeof(temp));
 
        for(int j=1;j<=b[0];j++)//从i开始的地方,复制数组b到数组temp
            temp[j+i-1]=b[j];
        temp[0]=b[0]+i-1;
        while(compare(a,temp)>=0)//用减法模拟
        {
            c[i]++;
            int flag=compare(a,temp);
            if(flag==0)
                a[0]=0;
            else if(flag==1)
            {
                for(int j=1;j<=a[0];++j)
                {
                    if(a[j]<temp[j])
                    {
                        a[j]+=10;
                        a[j+1]--;
                    }
                    a[j]-=temp[j];
                }
                while(a[0]>0&&a[a[0]]==0)
                    a[0]--;
            }
        }
    }
 
    while(c[0]>0&&c[c[0]]==0)//删除前导0
        c[0]--;
 
    cout<<"商为:";
    if(c[0]<=0)//输出结果
        cout<<0<<endl;
    else
    {
        for(int i=c[0];i>0;i--)
            cout<<c[i];
        cout<<endl;
    }
 
    cout<<"余数为:";
    if(a[0]==0)//输出余数
        cout<<0<<endl;
    else
    {
        for(int i=a[0];i>0;i--)
            cout<<a[i];
        cout<<endl;
    }
 
    return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

谷神星ceres

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值