高精度算法详解
发布日期:2022-03-03 02:49:12 浏览次数:1 分类:技术文章

本文共 5100 字,大约阅读时间需要 17 分钟。

目录


前言

在我们进行一些运算的时候,时常会遇到些烦人的问题,例如:n!、2的n次方啊...

算这些东西,int也不够,longlong也不够,这可咋办?

别慌,高精度帮你解决


一、高精度算法是什么?

指参与运算的数范围大大超过了标准数据类型(整型,实型)能表示的范围的运算。他的原理就是模拟竖式计算

二、代码

1.数据处理

既然是模拟竖式计算,那么就要一位一位进行运算,所以这里可以用字符串输入或者字符数组输入。

//方式一:string s1,s2;cin>>s1>>s2;
//方式二,使用字符数组的时候要注意,字符数组要分配足够的空间char s1[200];char s2[200];cin>>s1>>s2;

数据是通过字符串输入的,不能够直接进行计算,需要转换成数字。我们选用最基本的转换储存方式,字符串的一个字符对应数组中的一个元素,把字符串的数字全部转换到一个数组中

另外一个问题,我们在模拟竖式计算时,是从低位向高位依次计算,但在内存中存储数据时,数组的低位对应数字的高位,例如存储"123"存入a[N]数组,a[0]存储的是数字的高位'1',为统一操作,我们将数组下标为1对应数的个位,数组下标为2的对应数的十位,以此类推,这也叫"对齐"操作。

位数可以存在a[0]的位置。

string s1,s2;int a[1000],b[1000];void transfer(){    int len1=s1.length();    a[0]=len1;//将输入数据的位数存储在整型数组的第一个元素    for(int i=0;i

2.加法

      两个正整数相加,c数组=a数组+b数组(注:a[1]表示a数据的个位),对应位置相加,得到的新数字如果超过9,把个位留下,高位进上去,完全模拟加法的竖式运算,注意各位是从数组下标1开始的,然后去掉计算结果中最高位的0,因为两数相加,可能不产生进位,因此需要把这种情况下最高位的0去掉,其实就是减小和的长度。

/**** @param a 加法* @param b 加数* @param c 和* @param len 数组c的长度*/void add(int a[],int b[],int c[],int len){    int d[len]={0};    int m=max(a[0],b[0]);    for(int i=1;i<=m;i++){        d[i]=a[i]+b[i];        d[i+1]=d[i]/10; //进位        d[i]=d[i]%10; //取进位后余下的数    }    int l=m+1;    while(d[l]==0&&l>1){        l--;    }    d[0]=l;    memcpy(c,d,len* sizeof(int));}​

3.减法

比较数组a和数组b的大小从而确定结果的正负号。

      两个正整数相减,a数组=大a数组-小b数组,通常情况下,需要比较参与运算的两个整数的大小,通过大数减小数,模拟普通的减法,从低位开始对应的减,不足就向高位借一。

使用大数减小数,并且去掉最高位的0。

/**** @param a* @param b a,b为参与计算的两个数* @param c 差* @param len 数组c的长度*/void sub(int a[], int b[], int c[], int len) {    int d[len] = {0};    for (int i = 1; i <= a[0]; i++) {        if (a[i] < b[i]) {            a[i] += 10;            a[i + 1]--;        }        d[i] = a[i] - b[i];    }    int l = a[0];    while (d[l] == 0 && l > 1) {        l--;    }    d[0] = l;    memcpy(c, d, len * sizeof(int));}

4.乘法

这里有2种方法:

1.高精度乘低精度

一大正整数乘以小正整数,即高精度数乘以一个整型数,c数组=a数组*k;
同加法类似,每一位都乘以k,再加上之前的进位,如果新得到的数字超过了10,那么个位留下,高位进上去。

/**** @param a 被乘数* @param k 乘数* @param c 积* @param len 数组c的长度*/void multipy(int a[],int k,int c[],int len){    int d[len]={0};    for(int i=1;i<=a[0];i++)    {        d[i]+=a[i]*k;        d[i+1]=d[i]/10;        d[i]=d[i]%10;    }    int p=a[0]+1;//防止出现大于10的位    while(d[p]>=10){        d[p+1]=d[p]/10;        d[p]=d[p]%10;        p++;    }}

去除最高位的0,首先需要确定这两个数相乘可能的最大位数长度:

//计算k的位数int f=k;int size=0;while(f!=0){    size++;    f/=10;}
//size是乘数k的位数,乘积的长度int l=a[0]+size;

完整的乘法函数

/**** @param a 被乘数* @param k 乘数* @param c 积* @param len 数组c的长度*/void multipy(int a[],int k,int c[],int len){    int d[len]={0};    for(int i=1;i<=a[0];i++)    {        d[i]+=d[i]+a[i]*k;        d[i+1]=d[i]/10;        d[i]=d[i]%10;    }    int l=a[0]+1;    while(d[l]!=0){        d[l+1] = d[l] / 10;        d[l]=d[l]%10;        l++;    }    //去除前导0    while(d[l]==0&&l>1){        l--;    }    d[0]=l;    memcpy(c,d,len* sizeof(int));}

2.高精度乘高精度

两大正整数相乘,c数组=a数组*b数组
模拟普通乘法竖式计算。

/**** @param a 被乘数* @param b 乘数* @param c 乘积* @param len 数组c的长度*/void multiply(int a[],int b[],int c[],int len){    int d[len]={0};    for(int i=1;i<=a[0];i++) {        for (int j = 1; j <= b[0]; j++)        {            d[i + j - 1] = a[i] * b[j] + d[i + j - 1];            d[i+j]+= d[i + j - 1] / 10;//进位            d[i + j - 1] = d[i + j - 1] % 10;        }    }    int l=a[0]+b[0];    while(d[l]==0&&l>1){        l--;    }    d[0]=l;//数组d拷贝导数组c    memcpy(c,d,len* sizeof(int));}

5.除法

这里也有2种方法:

1.高精度除低精度

大正整数除以小正整数,c数组=a数组÷b数,模拟除法竖式计算

/**** @param a 被除数* @param k 除数* @param c 商* @param l*/void divide(int a[],int k,int c[],int len){    int d[len]={0};    int x=0; //从高位开始除    for(int i=a[0];i>=1;i--){        d[i]=(x*10+a[i])/k;        x=(x*10+a[i])%k;    }//计算k的位数    int f=k;    int size=0;    while(f!=0){        size++;        f/=10;    }//size是成数k的位数    int l=max(a[0]-size+1,1);//去除前导0    while(d[l]==0&&l>1){        l--;    }    d[0]=l;//把数组d的数据拷贝给c    memcpy(c,d,len* sizeof(int));}

2.高精度除高精度

大正整数除以小正整数,c数组=a数组÷b数组

找到运算结果的最高位,从最高位一直循环到个位:

for(int i=a[0]-b[0]+1;i>=1;i--){//a[0]-b[0]+1运算结果的最高位//除法运算}

数组a从最高位到当前位与数组b进行比较

/*** 比较大小* @param a 被除数* @param b 除数* @param current 从最高位数到当前位置* @return*/bool compareab(int a[],int b[],int current){    if(a[0]-current+1>b[0]){        return true; //大    }else if(a[0]-current+1
=current;i--,j--){ if(a[i]==b[j]){ continue; }else{ return a[i]>b[j]; } } return 1; }}

数组a从最高位到当前位减数组b

/*** 减法* @param a 被除数* @param b 除数* @param current 从最高位数到当前位置* @return*/void deduce(int a[],int b[],int current){    for(int i=current,j=1;i<=a[0];i++,j++){        if(a[i]

补充前面循环中的除法处理代码:

/**** @param a* @param b* @param c* @param len 数组a和数组c的长度,通常情况下我们把a,b,c三个数组的长度都设置成相同*/void divide(int a[],int b[],int c[],int len){    int d[len]={0};    int a1[len];//使用a1进行计算,因为在计算过程中,被除数会被改变,因此拷贝一个数组参与运算    memcpy(a1,a,len* sizeof(int));    d[0]=1;//防止输入的被除数小于除数,无输出结果。    for(int i=a[0]-b[0]+1;i>=1;i--){        int t=0;        while(compareab(a1,b,i)){            deduce(a1,b,i);            t++;        }        d[i]=t;    }    int l=max(a[0]-b[0]+1,1);//去除前导0    while(d[l]==0&&l>1){        l--;    }    d[0]=len;//把数组d的数据拷贝给c    memcpy(c,d,len* sizeof(int));}

因为都是固定代码,所以就不找例题啦

转载地址:https://blog.csdn.net/jhfhfhu/article/details/120470229 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:c++贪心详解
下一篇:快速幂算法——带你从零开始一步一步优化

发表评论

最新留言

逛到本站,mark一下
[***.202.152.39]2024年04月21日 06时39分47秒