本文共 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 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!