因为日常中没有把一些算法模板存储下来的习惯,而高精度算法又是如此地麻gui烦chu,于是便产生了放在blog里的想法。
高精度加法
#include<iostream>
using namespace std;
// 采用数组倒序存储数字方便进位计算
int a[100],b[100],c[100];
void add()
{
int x=0,i=1;
// 加法运算
for(;i<=a[0]||i<=b[0];i++)
{
// c数组为结果数组 它等于a[i]+b[i]+x x为当前累计的进位
c[i]=a[i]+b[i]+x;
// 计算进位
x=c[i]/10;
c[i]%=10;
}
// 若有剩下的进位,则累加进去
c[i]=x;
}
main()
{
string a1,a2;
cin>>a1>>a2;
// 倒序存储数字 a[0]记录数字长度
for(int i=a1.size()-1,j=1;i>=0;i--,j++)
{
a[j]=a1[i]-'0';
a[0]++;
}
for(int i=a2.size()-1,j=1;i>=0;i--,j++)
{
b[j]=a2[i]-'0';
b[0]++;
}
add();
// 设置一个flag标记是否遍历完前导0
bool flag=0;
// 倒序输出
for(int i=99;i>=1;i--)
{
if(!c[i]&&!flag)continue;
flag=1;
cout<<c[i];
}
}
# 高精度减法
#include<iostream>
using namespace std;
int a[100],b[100],c[100];
void subtract()
{
for(int i=1;i<=a[0]||i<=b[0];i++)
{
// 若不够减,则借一位说话
if(a[i]<b[i])a[i]+=10,a[i+1]--;
c[i]=a[i]-b[i];
}
}
main()
{
// 字符输入&存储 与高精加法类似
string a1,a2;
cin>>a1>>a2;
// 需要注意,若a1比a2来得短,或a1比a2小,则输出负号-
if(a1.size()<a2.size()||(a1.size()==a2.size()&&a1<a2))swap(a1,a2),cout<<'-';
// 这里写的时候没注意,输出总是少一位 i应该设置为≥0 否则数字的最高位不会读入
for(int i=a1.size()-1,j=1;i>=0;i--,j++)
{
a[j]=a1[i]-'0';
a[0]++;
}
for(int i=a2.size()-1,j=1;i>=0;i--,j++)
{
b[j]=a2[i]-'0';
b[0]++;
}
subtract();
// 同上,标记前导0
bool flag=0;
for(int i=100-1;i>=1;i--)
{
if(!c[i]&&!flag)continue;
flag=1;
cout<<c[i];
}
}
# 高精度乘法
#include<iostream>
using namespace std;
int a[100],b[100],c[100];
void multiply()
{
int i=1,j;
for(;i<=a[0];i++)
{
// x为进位
int x=0;
// 对于b中的每一位
for(j=1;j<=b[0];j++)
{
// 将c的第i+j-1位累加入乘积以及当前进位
c[i+j-1]+=a[i]*b[j]+x;
// 计算进位
x=c[i+j-1]/10;
c[i+j-1]%=10;
}
// 将剩余的进位计入下一位
c[i+j-1]=x;
}
}
main()
{
// 完全一样的数据读入
string a1,a2;
cin>>a1>>a2;
for(int i=a1.size()-1,j=1;i>=0;i--,j++)
{
a[j]=a1[i]-'0';
a[0]++;
}
for(int i=a2.size()-1,j=1;i>=0;i--,j++)
{
b[j]=a2[i]-'0';
b[0]++;
}
multiply();
bool flag=0;
for(int i=100-1;i>=1;i--)
{
if(!c[i]&&!flag)continue;
flag=1;
cout<<c[i];
}
}
# 高精度除法(除数为非高精度数)
#include<iostream>
#include<string>
#include<cstring>
using namespace std;
int a[110],b,c[123456],mod;
void divide()
{
// 此次除法的余数
int x=0;
// 对于每一位被除数,商=上一次余数*10+此位被除数 除以 除数
for(int i=1;i<=a[0];i++)
{
c[i]=(x*10+a[i])/b;
x=(x*10+a[i])%b;
}
// 剩下的除不尽的即为余数
mod=x;
}
main()
{
// 初始化为-1方便处理后缀0的情况
memset(c,-1,sizeof(c));
string a1,a2;
cin>>a1>>b;
// 对于除法,因为无需进位,故正序存储
for(int i=1;i-1<a1.size();i++)
{
a[i]=a1[i-1]-'0';
a[0]++;
}
divide();
// 同样,记前导0状态
bool flag=0;
for(int i=1;i<123456&&c[i]!=-1;i++)
{
if(!c[i]&&!flag)continue;
flag=1;
cout<<c[i];
}
if(!flag)cout<<0;
}
# 高精度除法(除数为高精度数)
#include<iostream>
#include<string>
#include<cstring>
using namespace std;
int a[100],b[100],c[100];
// 因为除数也是高精度数,对于这种比较骚气的处理
// 我们采用减法模拟除法,对于每一位都逐个减去除数*位权
// 如对于666/3 我们先用666-300-300=66 商记为2 再66-30-30=6 商记为22 最后6-3-3=0 商为222
// 比较高精度数a与高精度数b
int compare(int a[],int b[])
{
int i;
if(a[0]>b[0])return 1;
if(a[0]<b[0])return -1;
for(i=a[0];i>0;i--)
{
if(a[i]>b[i])return 1;
if(a[i]<b[i])return -1;
}
return 0;
}
// 高精度数 a-=b
void subtract(int a[],int b[])
{
int flag=compare(a,b),i;
if(!flag)
{
a[0]=0;
return;
}
// 若a>b,则进行高精度减法
if(flag==1)
{
for(int i=1;i<=a[0];i++)
{
if(a[i]<b[i])
{
a[i+1]--;
a[i]+=10;
}
a[i]-=b[i];
}
// 删去前导0
while(a[0]>0&&a[a[0]]==0)a[0]--;
}
}
main()
{
string m,n;
int i,j;
cin>>m>>n;
// 因为要进行减法,故逆序存储数字
for(i=m.size()-1,j=1;i>=0;i--,j++)a[j]=m[i]-'0',a[0]++;
for(i=n.size()-1,j=1;i>=0;i--,j++)b[j]=n[i]-'0',b[0]++;
int temp[100];
// 商的位数=被除数位数-除数位数+1
int len=a[0]-b[0]+1;
// 从高位到低位进行运算
for(i=len;i>0;i--)
{
memset(temp,0,sizeof(temp));
// temp为b*位权
// 为了达到此目的,我们采用错位存储的方式 对于每一位j,加上此时位数i后-1(因为j是从1开始的)
for(j=1;j<=b[0];j++)temp[i+j-1]=b[j];
// 记录此时temp的位数
temp[0]=b[0]+i-1;
// 以减法模拟除法
while(compare(a,temp)>=0)c[i]++,subtract(a,temp);
}
// 前导0标记
bool flag=0;
// 输出商
for(i=99;i>=1;i--)
{
if(!flag&&!c[i])continue;
flag=1;
cout<<c[i];
}
if(!flag)cout<<0;
cout<<endl;
flag=0;
// 输出余数
for(i=a[0];i>=1;i--)
{
if(!flag&&!a[i])continue;
flag=1;
cout<<a[i];
}
if(!flag)cout<<0;
}