高精度算法是模拟思想中比较典型的部分,这里列举了一些典型的我个人总结的精度算法(新手入门),一些基本的概念大家可以自己百度查阅
注意这里进行运算的数据都是非负数,但是结果不一定是非负数
1.高精加低精
这里是用一个大数依次加若干个小数,即从90001加到95000共5000次加法,注意这里没有采用输入,如果要用数组存储位数,须用到sstream头文件,将int类型转换为string类型
//大数加小数(无输入)
#include<iostream>
#include<string>
#include<sstream>
#define MAXN 99+4
using namespace std;
int main()
{
int temp=9;
int a[MAXN]={};
stringstream st;
for(int i=0;i<99;i++)
{
st<<temp;//将99个9放入st
}
string s;
s=st.str();//将99个9放入s
for(int i=0;i<s.size();i++)
{
a[i]=s[s.size()-1-i]-'0';//逆序存放,即个位在a[0],依次往后
}
for(int i=90001;i<=95000;i++)//从90001加到95000
{
int jw=0;
a[0]+=i;//把小数加入个位
for(int j=0;j<MAXN;j++)//接下来处理进位
{
a[j]+=jw;//加上上一个进位
jw=a[j]/10;//计算下一次进位的值
a[j]%=10;//进位后的结果
}
}
int len=MAXN;
for(int i=len-1;i>=0;i--)//删除前导0
{
if(a[i]==0&&len>1)//注意值为0的情况,即使这里不可能,这是一种习惯
{
len--;
}
else
{
break;
}
}
for(int i=len-1;i>=0;i--)//逆序遍历输出
{
cout<<a[i];
}
cout<<endl;
2.高精加高精
这里采用有输入的情况,先用string对象存储数字,再放入int数组中,高精的算法同样适用于低精,代码如下
//大数加大数
#include<iostream>
#include<string>
#include<algorithm>
#define MAXN 100+4
using namespace std;
int main()
{
string s1;
string s2;
int a[MAXN]={};
int b[MAXN]={};
cin>>s1>>s2;//输入两个大数
for(int i=0;i<s1.size();i++)
{
a[i]=s1[s1.size()-1-i]-'0';//将大数逆序放入a数组
}
for(int i=0;i<s2.size();i++)
{
b[i]=s2[s2.size()-1-i]-'0';//同上
}
/*它规定了一个加法能够达到的
最大的可能位数,以此之后遍历
的时候不用遍历到MAXN*/
int lena=max(s1.size(),s2.size())+1;//+1是因为可能进位
int jw=0;
for(int i=0;i<lena;i++)
{
a[i]+=b[i]+jw;
jw=a[i]/10;
a[i]%=10;
}
for(int i=lena-1;i>=0;i--)//删除前导0
{
if(a[i]==0&&lena>1)
{
lena--;
}
else
{
break;
}
}
for(int i=lena-1;i>=0;i--)//逆序遍历
{
cout<<a[i];
}
cout<<endl;
}
3.高精减低精(低精减高精)
这里和加法区别不大,依然用个位去减低精,然后向上借位即可,如果是低精减高精,加个负号,其余不变,代码如下
//大小数互减
#include<iostream>
#include<string>
#define MAXN 100+4
using namespace std;
int main()
{
string s;
cin>>s;
int b;
cin>>b;
int a[MAXN]={};
for(int i=0;i<s.size();i++)
{
a[i]=s[s.size()-1-i]-'0';//放入数组
}
int c=0;//借位
a[0]-=b;//用个位减去小数
for(int i=0;i<s.size();i++)
{
a[i]-=c;//减去借位
c=0;//重置借位为0
if(a[i]<0)
{
while(a[i]<0)
{
a[i]+=10;//每次从下一位借1
c++;//借位加1
}
}
else//这里到末尾都没有借位,不动即可
{
break;
}
}
int len=s.size();
for(int i=len-1;i>=0;i--)//删前导0
{
if(a[i]==0&&len>1)
{
len--;
}
else
{
break;
}
}
for(int i=len-1;i>=0;i--)
{
cout<<a[i];
}
cout<<endl;
return 0;
}
4.高精减高精
这里判断了一下大小,用大减小即可,其他无变化,代码如下
//大数减大数
#include<iostream>
#include<string>
#define MAXN 100+4
using namespace std;
int main()
{
string s1;
string s2;
cin>>s1>>s2;
if(s1.size()<s2.size()||s1.size()==s2.size()&&s1<s2)//判断大小
{
cout<<"-";
swap(s1,s2);
}
int a[MAXN]={};
int b[MAXN]={};
for(int i=0;i<s1.size();i++)
{
a[i]=s1[s1.size()-1-i]-'0';
}
for(int i=0;i<s2.size();i++)
{
b[i]=s2[s2.size()-1-i]-'0';
}
int c=0;
for(int i=0;i<s1.size();i++)
{
a[i]-=b[i]+c;
c=0;
while(a[i]<0)
{
a[i]+=10;
c++;
}
}
int len=s1.size();
for(int i=len-1;i>=0;i--)
{
if(a[i]==0&&len>1)
{
len--;
}
else
{
break;
}
}
for(int i=len-1;i>=0;i--)
{
cout<<a[i];
}
cout<<endl;
return 0;
}
5.高精乘低精
这里只要注意低精会和高精的每一位相乘,注意进位即可,非常简单,这种题目典型的应用就是高阶乘的运算,代码如下
#include<iostream>
#include<string>
#define MAXN 100+4
using namespace std;
int main()
{
string s;
int b;
int a[MAXN]={};
cin>>s;
cin>>b;
for(int i=0;i<s.size();i++)
{
a[i]=s[s.size()-1-i]-'0';
}
int jw=0;
for(int i=0;i<MAXN;i++)
{
a[i]=a[i]*b+jw;
jw=a[i]/10;
a[i]%=10;
}
int len=MAXN;
for(int i=len-1;i>=0;i--)
{
if(a[i]==0&&len>1)
{
len--;
}
else
{
break;
}
}
for(int i=len-1;i>=0;i--)
{
cout<<a[i];
}
cout<<endl;
return 0;
}
6.高精乘高精
大数乘大数在大数乘小数的基础上延申,即交叉相乘,有些代码把交叉相乘和处理进位放在一起,但我觉得不直观,即使少遍历了一遍,但是然并卵,这里交叉相乘后再统一处理进位,看起来爽一些,代码如下
//大数乘大数
#include<iostream>
#include<string>
#define MAXN 100+4
using namespace std;
int main()
{
string s1;
string s2;
int a[MAXN]={};
int b[MAXN]={};
/*由于a数组的数据要多
次用到,所以决定另开辟
一个数组*/
int c[MAXN]={};
cin>>s1;
cin>>s2;
for(int i=0;i<s1.size();i++)
{
a[i]=s1[s1.size()-1-i]-'0';
}
for(int i=0;i<s2.size();i++)
{
b[i]=s2[s2.size()-1-i]-'0';
}
for(int i=0;i<s1.size();i++)//采用交叉相乘
{
for(int j=0;j<s2.size();j++)
{
c[i+j]+=a[i]*b[j];
}
}
int jw=0;
for(int i=0;i<MAXN;i++)//开始处理进位
{
c[i]+=jw;
jw=c[i]/10;
c[i]%=10;
}
int len=MAXN;
for(int i=len-1;i>=0;i--)
{
if(c[i]==0&&len>1)
{
len--;
}
else
{
break;
}
}
for(int i=len-1;i>=0;i--)
{
cout<<c[i];
}
cout<<endl;
return 0;
}
7.高精除低精
这里用每一位去除除数,不够则把余数放到下一位去除,找到被除数就能得到商和余数,比较简单,代码如下
//大数除小数
#include<iostream>
#include<string>
#define MAXN 100+4
using namespace std;
int main()
{
string s;
cin>>s;
int a[MAXN]={};
int b;
cin>>b;
for(int i=0;i<s.size();i++)
{
a[i]=s[s.size()-1-i]-'0';
}
int x=0;
for(int i=s.size()-1;i>=0;i--)//一位一位除
{
int temp=x*10+a[i];//这是每次除法的被除数
a[i]=temp/b;//每次除法的商
x=temp%b;//每次得到的余数
}
int len=s.size();
for(int i=len-1;i>=0;i--)
{
if(a[i]==0&&len>1)
{
len--;
}
else
{
break;
}
}
for(int i=len-1;i>=0;i--)
{
cout<<a[i];
}
cout<<"......"<<x<<endl;
return 0;
}
8.高精除高精
这里相对比较复杂,首先是数组比较与移位函数,数组比较很简单,移位函数就是将数组高位对齐,这里开辟了一个temp数组用来存储高位对齐后的除数,即扩大倍数后的除数,原理上与减法相同,但是如果只有减法必TLE,移位合理扩大了倍数,我之前也写了一个相似的代码,但是因为效率太低而舍弃,扩大倍数也需要合理的方法,否则不能保证算法的效率,代码如下
#include<iostream>
#include<string>
#include<sstream>
#include<cstring>
#define MAXN 100+4
using namespace std;
/*长度需要全局声明,
以便函数使用*/
int lena;
int lenb;
int lenc;
int lentemp;
int cmp(int *a,int *b)//比较数组的数据大小
{
stringstream st1;
stringstream st2;
for(int i=MAXN-1;i>=0;i--)
{
st1<<a[i];
st2<<b[i];
}
string s1=st1.str();
string s2=st2.str();
if(s1==s2)
{
return 0;
}
else if(s1.size()<s2.size()||s1.size()==s2.size()&&s1<s2)
{
return -1;
}
else if(s1.size()>s2.size()||s1.size()==s2.size()&&s1>s2)
{
return 1;
}
}
/*移位函数,能够使除数与被除数
高位对齐,将b数组的数移到temp数组
的dex下标的位置*/
void numcpy(int *b,int *temp,int dex)
{
for(int i=0;i<lenb;i++)
{
temp[i+dex]=b[i];
}
}
int main()
{
string s1;
string s2;
int a[MAXN]={};
int b[MAXN]={};
int c[MAXN]={};
int temp[MAXN]={};
cin>>s1>>s2;
lena=s1.size();
lenb=s2.size();
/*+1是考虑到被除数
位数减去除数位数不
一定是商的位数,
例如625/25=25*/
lenc=lena-lenb+1;
for(int i=0;i<s1.size();i++)
{
a[i]=s1[s1.size()-1-i]-'0';
}
for(int i=0;i<s2.size();i++)
{
b[i]=s2[s2.size()-1-i]-'0';
}
for(int i=lenc-1;i>=0;i--)
{
memset(temp,0,sizeof(temp));//temp数组清空
numcpy(b,temp,i);//高位对齐
while(cmp(a,temp)>=0)//被除数比temp大
{
c[i]++;//商的第i+1位加1
for(int j=0;j<lena;j++)//高精度减法,详情见之前的代码
{
if(a[j]<temp[j])
{
a[j+1]--;
a[j]+=10;
}
a[j]=a[j]-temp[j];
}
}
}
for(int i=lenc-1;i>=0;i--)//商删除前导0
{
if(c[i]==0&&lenc>1)
{
lenc--;
}
else
{
break;
}
}
for(int i=lena-1;i>=0;i--)//余数删除前导0
{
if(a[i]==0&&lena>1)
{
lena--;
}
else
{
break;
}
}
for(int i=lenc-1;i>=0;i--)
{
cout<<c[i];
}
cout<<"......";
for(int i=lena-1;i>=0;i--)
{
cout<<a[i];
}
cout<<endl;
return 0;
}
/*输出效果
输入样例
150 32
输出样例
4......22
输入样例
123123123123123123123123123123123 123456
输出样例
997303680040849558734473197......114291*/