高精度算法(加法,减法,乘法,除法)
(弱驹一枚,有错误欢迎来指点,谢谢)
哈喽!
在我们日常 敲 (qian) 代 (tu) 码 (guang) 时 (ming), 是不是会经常遇见高精度的 加法, 减法, 乘法, 除法 呢?,相信你遇到过需要用到高精度的题目。在我们还没接触高精度算法的时候,当需要把两个贼大的数相加的时候,我们会想到把两个变量定义成(long long型 ,double型) 这两种应该是我们还没接触高精度算法时所能想到的(定义较大变量),其中double(双精度浮点数)使用 64 位(8字节) 来储存一个浮点数。 它 仅仅 可以表示十进制的15或16位有效数字,负值取值范围为 -1.7976E+308 到 -4.94065645841246544E-324,正值取值范围为 4.94065645841246544E-324 到 1.797693E+308
所以当我们要进行两个大数相加时,上面两种是远远不够的,所以我们需要学高精度算法
例1、高精度加法
先上例题
题目描述
高精度加法,x相当于a+b problem,不用考虑负数
输入输出格式
输入格式:
分两行输入a,b<=10^500
输出格式:
输出只有一行,代表A+B的值
( 10^500 非常大,所以要用高精度算法来解决这道题 )
方法要领
肝就完了
正着读入,倒着输出,用字符串数组进行模拟加法
1、定义字符数组或字符串
(char str[666],str1[666],str2[666]; ) | | ( string str ,str1, str2;) ?
///C++ #include
///个人比较喜欢用定义string型字符串,有很多方便的功能
string str1,str2;
2、计算字符串的长度
///利用string 直接得出字符串长度,很方便
int length1=str1.length();
int length2=str2.length();
3、比较len1 len2 ,将较小者补位(用0进行部位,位数补到与较大者一致)
if(length1>=length2)
for(int i=1; i<=length1-length2; i++)
str2 = "0" + str2;
else
for(int i=1; i<=length2-length1; i++)
str1 = "0" + str1;
///把位数补齐时,定义length=str1.length();
length1=str1.length();
4、进行加法(关键一步)
int nre; ///该进位后该位的数
int pre=0; ///储存 进位的变量
for(int i=length1-1;i>=0;i--){///倒着输出
nre=str1[i]-'0'+str2[i]-'0'+pre;
///将字符数字转换位数字再加上进位的数
pre=nre/10; ///进位
nre%=10; ///该进位后该位的数
s=char(nre+'0')+s; ///强制类型转化
}
if(pre!=0) s=char(pre+'0')+s; ///若不为0,则进行存入
}
5、最后一步来个愉快的输出(会WA的 )就行
最后上总码
#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> P;
#define INF 0x3f3f3f3f
#define MAX_N 555
#define ll long long
int main()
{
string str,str1,str2;
int nre;
int pre=0;
cin>>str1>>str2;
int length1=str1.length();
int length2=str2.length();
if(length1>=length2)
for(int i=1; i<=length1-length2; i++) str2 = "0" + str2;
else
for(int i=1; i<=length2-length1; i++) str1 = "0" + str1;
///把位数补齐时,定义length=str1.length();
length1=str1.length();
for(int i=length1-1;i>=0;i--){///倒着输出
nre=str1[i]-'0'+str2[i]-'0'+pre;
///将字符数字转换位数字再加上进位的数
pre=nre/10; ///进位
nre%=10; ///该进位后该位的数
str=char(nre+'0')+str; ///强制类型转化
}
if(pre!=0) str=char(pre+'0')+str; ///若不为0,则进行存入
cout<<str<<endl;
}
**例2、 高精度减法 **
上题
高精度减法
输入输出格式
输入格式:
两个整数a,b(第二个可能比第一个大)
输出格式:
结果(是负数要输出负号)
需注意
1、是两个正数相减,要注意是 大减小,如果是小减大(需要注意从高位借1来减去地位, 比如 18-9 8小于9,不能相减,所以从十位借1来减9,也就是小学减法)
2、
///str1 小于str2 时后相减为负,则只需交换过来,然后相减再取负就行
if(str1.length()<str2.length()) {
cout<<'-';
swap(str1, str2);
}
3、去除多余前导零
这里利用到了c++里面的 STL(StandardTemplate Library),即标准模板库
str.erase( 0 , str.find_first_not_of( '0' ) );
///用来去除我们得出结果中多余的前导0;
if(!str.length()) ///特判 存在两者相减为零的情况
cout<<0<<endl;
STL不清楚的可以找一下
度娘
上代码
#include <bits/stdc++.h>
using namespace std;
int main()
{
string str,str1,str2;
cin>>str1>>str2;
if(str1.length()<str2.length()) {
cout<<'-';
swap(str1, str2);
}
int temp; ///两数相减后的数 也就是商
int flag=0; ///小减大时借位专用
temp=str1.length()-str2.length();
for(int i=str2.length()-1; i>=0; i--) {
if(str1[temp+i] < str2[i]+flag){ ///判断每个位数时 是否 小减大
///例如。18-9 8-9小于0,则需要从10位中取1来减去个位中的9
str=char(str1[temp+i]-str2[i]-flag+'0'+10)+str; ///小减大的处理方法,加上10,再进上位1,等下一起减掉
flag=1; ///小减大
}
else {
str=char(str1[temp+i]-str2[i]-flag+'0')+str; ///大减小,不需要加 10和进位
flag=0;/// 大减小
}
}
for(int i=temp-1; i>=0; i--) {
if( str1[i] - flag >= '0') { /// 道理同上
str=char(str1[i]-flag)+str; ///强制类型转化
flag=0;///
}
else {
str=char(str1[i]-flag+10)+str;
flag=1;
}
}
str.erase(0,str.find_first_not_of('0'));
///用来去除我们得出结果中多余的前导0;
if(!str.length())///特判两者相减为零的情况
cout<<0<<endl;
else
cout<<str<<endl;
}
**例3、 高精度乘法 **
高精度乘法
这次用字符数组来做
关键步骤
1、计算长度
length1=strlen(str1);
length2=strlen(str2);
2、类型转化
for(int i=1;i<=length1;++i)
/// 将字符串转化为整型
s[i]=str1[length1-i]-'0';
///length-i操作是方便后面从低位往高位就行乘法
for(int i=1;i<=length2;++i)
ss[i]=str2[length2-i]-'0';
3、从低位开始进行乘法
for(int i=1;i<=length1;++i)
for(int j=1;j<=length2;++j)
str[i+j-1]+=(s[i]*ss[j]);
length=length1+length2;
4、进位操作
for(int i=1;i<length;++i)
if(str[i]>9){ ///大于9时则需要进位
str[i+1]+=str[i]/10; ///进位操作
str[i]%=10;
}
5、消除前导零 判断是否相乘为0
while(str[length]==0 && length>1)
length--; ///消除前导0
6、倒序输出
上代码
#include<bits/stdc++.h>
using namespace std;
#define maxx 50005
char str1[maxx], str2[maxx];///字符数组
int str[maxx];
int s[maxx],ss[maxx];///字符串转化成数字储存的数组
int length,length1,length2;
int main()
{
cin>>str1>>str2;
length1=strlen(str1);
length2=strlen(str2);
for(int i=1;i<=length1;++i)/// 将字符串转化为整型
s[i]=str1[length1-i]-'0';///length-i操作是方便后面从低位往高位就行乘法
for(int i=1;i<=length2;++i)
ss[i]=str2[length2-i]-'0';
for(int i=1;i<=length1;++i)
for(int j=1;j<=length2;++j)
str[i+j-1]+=(s[i]*ss[j]);///从低位向高位乘
length=length1+length2;
for(int i=1;i<length;++i)
if(str[i]>9){ ///大于9时则需要进位
str[i+1]+=str[i]/10; ///进位操作
str[i]%=10;
}
while(str[length]==0 && length>1) ///消除前导0
length--;
for(int i=length;i>=1;--i)
cout<<str[i];
printf("\n");
return 0;
}
4、高精度除法
1
int comp(int str1[],int str2[]){ ///长度比较
if(str1[0]>str2[0]) return 1;
if(str1[0]<str2[0]) return -1;
for(int i=str1[0];i>0;i--) {///从高位到低位比较
if(str1[i]>str2[i]) return 1;
if(str1[i]<str2[i]) return -1;
}
return 0;
}
2\ 减法 计算str1=str1-t
int book;
book=comp(str1,t);
if(book==0){/// book等于0,说明两者相等
str1[0]=0;
return;
}
if(book==1) {///book等于1,str1>t;
for(int i=1;i<=str1[0];i++) {///一直提到的借位 若不够向上借位
if(str1[i]<t[i]) {
str1[i+1]--;/// 借位则减1
str1[i]+=10;///低位数加10
}
str1[i]-=t[i];
}
while(str1[0]>0&&str1[str1[0]]==0)///通过判断是否有前导零,删除前导0
str1[0]--;
return;
}
3 进行除法操作
length=length1-length2+1;
str[0]=length;
for(int i=length;i>=1;i--){
for(int x=1;x<=length2;x++)
t[i+x-1]=str2[x]; ///将str2赋值到t数组中
t[0]=length2+i-1;
while(comp(str1,t)>=0){
str[i]++; the_subtraction(str1,t);///调用做减法的函数
}
}
其他需要的步骤基本于上面所讲的差不多,例如去 前导零等一些必要的操作
上代码
#include<bits/stdc++.h>
using namespace std;
#define maxx 10050
int str1[maxx],str2[maxx],str[maxx];
char a[maxx],b[maxx];
int length,length1,length2,t[maxx];
int comp(int str1[],int str2[]){ ///长度比较
if(str1[0]>str2[0]) return 1;
if(str1[0]<str2[0]) return -1;
for(int i=str1[0];i>0;i--) {///从高位到低位比较
if(str1[i]>str2[i]) return 1;
if(str1[i]<str2[i]) return -1;
}
return 0;
}
void the_subtraction (int str1[],int t[])
{
int book;
book=comp(str1,t);
if(book==0){/// book等于0,说明两者相等
str1[0]=0;
return;
}
if(book==1) {///book等于1,str1>t;
for(int i=1;i<=str1[0];i++) {///一直提到的借位 若不够向上借位
if(str1[i]<t[i]) {
str1[i+1]--;/// 借位则减1
str1[i]+=10;///低位数加10
}
str1[i]-=t[i];
}
while(str1[0]>0&&str1[str1[0]]==0)///通过判断是否有前导零,删除前导0
str1[0]--;
return;
}
}
int main(){
cin>>a>>b;int book;
length1=strlen(a);/// a的长度
length2=strlen(b);///b的长度
str1[0]=length1; ///将str[0]赋值为str1长度方便调用函数时进行值传递
str2[0]=length2;
for(int i=1;i<=length1;++i) str1[i]=a[length1-i]-'0';
///类型转化将字符串转化为整型数
for(int i=1;i<=length2;++i) str2[i]=b[length2-i]-'0';
length=length1-length2+1;
str[0]=length;
for(int i=length;i>=1;i--){
for(int x=1;x<=length2;x++)
t[i+x-1]=str2[x]; ///将str2赋值到t数组中
t[0]=length2+i-1;
while(comp(str1,t)>=0){
str[i]++; the_subtraction(str1,t);///调用做减法的函数
}
}
while(length>0 && str[length]==0) length--; ///去掉前导0
if(length==0) ///大除小则为0
printf("0");
else
for(int i=length;i>=1;i--)
printf("%d",str[i]);
printf("\n");
return 0;
}
好了,这次的高精度算法已经讲完了,高精度算法可以用很多不同种代码去实现,我用的只是其中的一种,嘻嘻
若有错误,麻烦指出来,一起交流,一起进步