高精度学习笔记

高精度学习笔记

c语言中任意数据类型都是有范围的,当一个数的范围超过了任意一个范围,那么这个数就被称为高精度数。

输入与储存

通常是用字符串来储存高精度数,每一个元素对应一位。例如:99100,数组储存便是
a[1]=0;
a[2]=0;
a[3]=1;

注意:因为我们用字符串来储存高精度数,所以数的低位也要对应字符数组的低位。
另外我们也要将高精度数的位数储存在a[0]的位置。那么上面的例子中a[0]=5;

a[0]a[1]a[2]a[3]a[4]a[5]
500199

代码实现如下:

#include<cstdio>
#include<cstring>
#define MAXLEN 240//最大的长度为240
int a[MAXLEN+10];
char s[MAXLEN+10];
int main()
{
    scanf("%s",s);
    a[0]=strlen(s);
    for(int i=0;i<a[0];i++)
        a[a[0]-i]=s[i]-'0';
    for(int i=a[0];i>0;i--)
        printf("%d",a[i]);
}

加法

假定两个数a,b相加,在高精度中我们依次将它们的相应的位加到一个c数组中。然后进行进位处理,如果这位的数超过了10那么就向它的上一位进1。最后将高位的0去掉。即:

  • 相加到另一个数组
  • 进位
  • 去掉高位的0

代码实现如下:

#include<cstdio>
#include<cstring>
#include<algorithm>
#define MAXLEN 240
using namespace std;
int a[MAXLEN+10],b[MAXLEN+10],c[MAXLEN+10];
char s[MAXLEN+10];
int main()
{
    scanf("%s",s);
    a[0]=strlen(s);
    for(int i=0;i<a[0];i++)
        a[a[0]-i]=s[i]-'0';
    memset(s,0,sizeof(s));
    scanf("%s",s);
    b[0]=strlen(s);
    for(int i=0;i<b[0];i++)
        b[b[0]-i]=s[i]-'0';
    c[0]=max(a[0],b[0]);
    for(int i=1;i<=c[0];i++)
        c[i]=a[i]+b[i];
    c[0]++;//加法最多进一位
    for(int i=1;i<=c[0];i++)
    {
        c[i+1]+=c[i]/10;
        c[i]%=10;
    }
    while(c[0]>1&&c[c[0]]==0)
        c[0]--;
    for(int i=c[0];i>0;i--)
        printf("%d",c[i]);
}

减法

依照由低位至高位的顺序进行减法运算。在每一次位运算中,若出现不够减的情况,则向高位借位。在进行了减运算后,若高位为0,则要减少结果的长度。

  • 进行减法
  • 处理借位
  • 去除高位的0

代码如下:

#include<cstdio>
#include<cstring>
#include<algorithm>
#define MAXLEN 240
using namespace std;
int a[MAXLEN+10],b[MAXLEN+10],c[MAXLEN+10];
char s[MAXLEN+10];
int main()
{
    bool f=0;
    scanf("%s",s);
    a[0]=strlen(s);
    for(int i=0;i<a[0];i++)
        a[a[0]-i]=s[i]-'0';
    memset(s,0,sizeof(s));
    scanf("%s",s);
    b[0]=strlen(s);
    for(int i=0;i<b[0];i++)
        b[b[0]-i]=s[i]-'0';
    int len=max(a[0],b[0]);
    if(memcmp(a,b,len)<0)
    {
        memcpy(c,a,(len+1)*4);
        memcpy(a,b,(len+1)*4);
        memcpy(b,c,(len+1)*4);
        f=1;
    }
    memset(c,0,sizeof(c));
    c[0]=len;
    for(int i=1;i<=c[0];i++)
        c[i]=a[i]-b[i];
    for(int i=1;i<=c[0];i++)
        if(c[i]<0)
        {
            c[i]+=10;
            c[i+1]-=1;
        }
    while(c[0]>1&&c[c[0]]==0)
        c[0]--;
    if(f)
        printf("-");
    for(int i=c[0];i>0;i--)
        printf("%d",c[i]);
}

乘法

首先我们要估计所需要的数组长度,然后被乘数从低位向高位逐位乘以乘数。

  • 逐位从低位向高位乘(较短的数每一个数都要乘以较长数的每一位)
  • 处理进位(因为我们并不知道题中数有多少为,所以在普通处理后要用一个while继续处理)
  • 去除高位的0

代码如下:

#include<cstdio>
#include<cstring>
#include<algorithm>
#define MAXLEN 500
using namespace std;
int a[MAXLEN+10],b[MAXLEN+10],c[MAXLEN*2+10];
char s[MAXLEN+10];
int main()
{
    scanf("%s",s);
    a[0]=strlen(s);
    for(int i=0;i<a[0];i++)
        a[a[0]-i]=s[i]-'0';
    memset(s,0,sizeof(s));
    scanf("%s",s);
    b[0]=strlen(s);
    for(int i=0;i<b[0];i++)
        b[b[0]-i]=s[i]-'0';
    c[0]=max(a[0],b[0]);
    if(memcmp(a,b,c[0])<0)//这里要让a数组是较长的数,b数组是较短的数。
    {
        memcpy(c,a,sizeof(a));
        memcpy(a,b,sizeof(b));
        memcpy(b,c,sizeof(c));
    }
    memset(c,0,sizeof(c));
    c[0]=max(a[0],b[0]);
    for(int i=1;i<=b[0];i++)
        for(int j=1;j<=a[0];j++)
            c[i+j-1]+=a[j]*b[i];//这里按照竖式计算的格式,所以i+j-1。
    for(int i=1;i<=c[0];i++)
    {
        c[i+1]+=c[i]/10;
        c[i]%=10;
    }
    c[0]++;
    while(c[c[0]]>=10)
    {
        c[c[0]+1]+=c[c[0]]/10;
        c[c[0]]%=10;
        c[0]++;
    }
    while(c[0]>1&&c[c[0]]==0)
        c[0]--;
    for(int i=c[0];i>0;i--)
        printf("%d",c[i]);
}

除法

基本方法是从被除数的最高位开始,逐位计算商和余数。存储商。余数则转移到下一次的被除数中。
注意在下一次的计算中,余数要乘以10,然后再加上当前位的被除数。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define MAXLEN 500
using namespace std;
int a[MAXLEN+10],b,c[MAXLEN*2+10];
int r;//余数
char s[MAXLEN+10];
int main()
{
    scanf("%s",s);
    a[0]=strlen(s);
    for(int i=0;i<a[0];i++)
        a[a[0]-i]=s[i]-'0';
    memset(s,0,sizeof(s));
    scanf("%d",&b);
    memset(c,0,sizeof(c));
    for(int i=a[0];i>0;i--)
    {
        r=r*10+a[i];
        c[i]+=r/b;
        r=r%b;
    }
    while(a[0]>1&&c[a[0]]==0)
        a[0]--;
    c[0]=a[0];
    for(int i=c[0];i>0;i--)
        printf("%d",c[i]);
    printf("\n%d",r);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值