专题篇:高精度
——————————————————————我是更新提示分割线———————————————————————
<第一次更新>仅供学习使用
—————————————————————我是华丽丽的正文分割线——————————————————————
高精度计算是一种用来处理大数据的算法,一般超过longlong的数据计算就需要使用高精度算法,上篇主要讲加法和减法。
加法
引入:A+B Problem
题目描述
高精度加法,相当于a+b problem,不用考虑负数
输入输出格式
输入格式:
分两行输入a,b<=10^1000
输出格式:
输出只有一行,代表A+B的值
解析:看似简单的题目,但数据量非常大,这时,就不可能用直接计算来实现了。
思考1):怎样储存数据?
对于大数据,可以采用字符串输入,转换为数组储存,每一个下标所在的位置储存一位数字,就可以方便的储存大数据了。
因此,我们有如下函数代码:
void scan()
{
cin>>s>>s1;
for(i=0;i<=s.size();i++)a[i]=int(s[i]-'0');//将字符的数字转换为数字的值
for(i=0;i<=s1.size();i++)b[i]=int(s1[i]-'0');
}
思考2):怎样计算?
对于计算,有了数组储存,我们很容易就能想到逐位相加,实际就是模拟我们小学中的列竖式计算。
但是,如果使用这种计算方式,对于最高位储存在最前面的数组,进位的处理就会变得相当麻烦,必须将储存方式推翻重来
所以,储存方式为逆序储存,方便进位处理。又有如下代码
void scan()
{
cin>>s>>s1;
for(i=0;i<=s.size();i++)a[s.size()-i]=int(s[i]-'0');//将当前数字储存到a,b数组的末端
for(i=0;i<=s1.size();i++)b[s1.size()-i]=int(s1[i]-'0');
}
这样,我们就能实现计算的基本代码了
void initi()
{
for(i=1;i<=1001;i++)
{
c[i]=b[i]+a[i];
}
}
思考3):怎样处理进位?
对于进位,直接采用数组的求余,加减就很容易实现
计算代码能做如下更改
void initi()
{
for(i=1;i<=1001;i++)
{
c[i]=c[i]+b[i]+a[i];
c[i+1]=c[i]/10;//进位处理:当然,c[i]不足10时,c[i]/10=0,c[i]%10=c[i]
c[i]=c[i]%10;
}
}
到这里为止,高精度加法的计算已经大体实现,最后一步时输出,不要忘记储存时是逆序储存的,输出时去掉数组末尾的0,逆序输出即可
代码如下
void print()
{
while(c[maxx]==0&&maxx>1)maxx--;
for(i=maxx;i>=1;i--)
{
cout<<c[i];
}
}
将各个函数组合,高精度加法的代码就能实现了
#include<bits/stdc++.h>
using namespace std;
int i,j,maxx=1001;
string s,s1;
int a[1050]={},b[1050]={},c[1050]={};
void scan()//输入
{
cin>>s>>s1;
for(i=0;i<=s.size();i++)a[s.size()-i]=int(s[i]-'0');
for(i=0;i<=s1.size();i++)b[s1.size()-i]=int(s1[i]-'0');
}
void initi()//计算
{
for(i=1;i<=1001;i++)
{
c[i]=c[i]+b[i]+a[i];
c[i+1]=c[i]/10;
c[i]=c[i]%10;
}
}
void print()//输出
{
while(c[maxx]==0&&maxx>1)maxx--;
for(i=maxx;i>=1;i--)
{
cout<<c[i];
}
}
int main()
{
scan();
initi();
print();
return 0;
}
减法
引入:A-B Problem
输入输出格式
输入格式:
两个整数a,b(第二个可能比第一个大)
输出格式:
结果(是负数要输出负号)
对于高精度减法,又有几个新的问题
思考1):怎样处理负数?
对于负数的处理,如果b>a,我们能直接输出一个负号,再交换a,b进行计算即可。
因此,我们首先需要一个比较两个高精度数的大小的函数,思路就是先比较长度,如果相同,再从高位到低位逐位比较。
int bigger(int k,int l)//k,l代表s1,s2的当前比较位
{
if(k==1&&l==1&&s1[k]==s2[l])return 0;
if(s1.size()>s2.size())return 1;
else
{
if(s2.size()>s1.size())return 2;
else
{
if(s1[k]>s2[l])return 1;
else
{
if(s2[l]>s1[k])return 2;
else
{
return bigger(k-1,l-1);
}
}
}
}
}
//返回1代表s1大,返回2代表s2大,返回0代表两数完全相等
这样,我们就能构成交换函数了
void change()
{
if(bigger(s1.size(),s2.size())==2)//比较两数
{
cout<<"-";
s3=s1;
s1=s2;
s2=s3;
}
}
思考2):怎样处理借位?
借位的处理实际和进位相似,只需将当前位加10,下一位减1即可
void initi()
{
for(i=1;i<=s1.size();i++)
{
c[i]=c[i]+a[i]-b[i];
if(c[i]<0)//借位处理
{
c[i]+=10;
c[i+1]--;
}
}
}
处理完这两个问题,高精度减法也基本完成了,组合输入输出就能构成代码。
#include<bits/stdc++.h>
using namespace std;
int i,j,maxx=10005;
string s1,s2,s3;
int a[10005]={},b[10005]={},c[10005]={};
void scan()//输入
{
cin>>s1>>s2;
for(i=0;i<=s1.size();i++)a[s1.size()-i]=int(s1[i]-'0');
for(i=0;i<=s2.size();i++)b[s2.size()-i]=int(s2[i]-'0');
}
int bigger(int k,int l)//比较
{
if(k==1&&l==1&&s1[k]==s2[l])return 0;
if(s1.size()>s2.size())return 1;
else
{
if(s2.size()>s1.size())return 2;
else
{
if(s1[k]>s2[l])return 1;
else
{
if(s2[l]>s1[k])return 2;
else
{
return bigger(k-1,l-1);
}
}
}
}
}
void change()//交换
{
if(bigger(s1.size(),s2.size())==2)
{
cout<<"-";
s3=s1;
s1=s2;
s2=s3;
}
}
void print()//输出
{
while(c[maxx]==0&&maxx>1)maxx--;
for(i=maxx;i>=1;i--)
{
cout<<c[i];
}
}
void initi()//计算
{
for(i=1;i<=s1.size();i++)
{
c[i]=c[i]+a[i]-b[i];
if(c[i]<0)
{
c[i]+=10;
c[i+1]--;
}
}
}
int main()
{
change();
scan();
initi();
print();
return 0;
}
到此为止,高精度的简单计算:加法,减法就实现了。
—————————————————————我是华丽丽的正文分割线——————————————————————
提示:下篇讲高精乘除
附件:高精运算模板,用于验证自己的程序是否准确
链接:https://pan.baidu.com/s/1bo9YN87
password:p0du
选择需要的高精计算,删除注释即可。
——————————————————————我是讲废话的分割线———————————————————————