基础高精度
小学奥数由于太简单 先咕了
写一下高精度吧...
先说一下高精度是来干嘛的,也可以直接跳过
由于a和b都比较大,所以不能直接使用语言中的标准数据类型来存储。对于这种问题,一般使用数组来处理。
定义一个数组A,A[0]用于存储a的个位,A[1]用于存储a的十位,依此类推。同样可以用一个数组B来存储b。
计算c = a + b的时候,首先将A[0]与B[0]相加,如果有进位产生,则把进位(即和的十位数)存入r,把和的个位数存入C[0],即C[0]等于(A[0]+B[0])%10。然后计算A[1]与B[1]相加,这时还应将低位进上来的值r也加起来,即C[1]应该是A[1]、B[1]和r三个数的和.如果又有进位产生,则仍可将新的进位存入到r中,和的个位存到C[1]中。依此类推,即可求出C的所有位。
最后将C输出即可。
先贴上两种代码
第一种 easy版本
[洛谷P1601](https://www.luogu.org/problemnew/show/P1601)
//看完后可以自己尝试打一下 在代码下面有注释
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
int main()
{
char a1[1000],b1[1000];
int a[1000],b[1000],c[1000],lena,lenb,lenc,i,x;
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
memset(c,0,sizeof(c));
scanf("%s",a1);scanf("%s",b1);//scanf就爆0!
lena=strlen(a1);
lenb=strlen(b1);
for(i=0;i<=lena-1;i++)
a[lena-i]=a1[i]-48;
for(i=0;i<=lenb-1;i++)
b[lenb-i]=b1[i]-48;
lenc=1;
x=0;
while(lenc<=lena||lenc<=lenb)
{
c[lenc]=a[lenc]+b[lenc]+x;
x=c[lenc]/10;
c[lenc]%=10;
lenc++;
}
c[lenc]=x;
if(c[lenc]==0)
lenc--;
for(i=lenc;i>=1;i--)
cout<<c[i];
cout<<endl;
return 0;
}
这个应该很好理解,以后贴上注释...注释来了
首先我们应该明白字符输入的顺序。
举个栗子 用数组a输入“1234” 这里的a[0]=1,a[1]=2,a[2]=3,a[3]=4,用b数组输入“5678”这里的b[0]=5,b[1]=6,b[2]=7,b[3]=8; 了解完这个,我们再回顾一下小学的竖式计算//学识浅薄不知道该咋捣鼓
1 2 3
- 6 9
=1 9 2
由上文可知,用数组a储存数的话就成了 a[0]=1,a[1]=2,a[3]=3; b[0]=6,b[1]=9,如果他们直接相加会出现旁边竖式那样的式子吗,请认真思考一下,我就不再模拟了。(思考很重要)
这个式子显而易见,它进位了,3+9=12,他会进位,我们应该怎么办呢
(请再思考一下)
好了接下来我们逐步讲解用法
一.
1.数组其实也可以不清0..但如果测多组数据,清0就ok
2.这几个数组尽量在200以上,要不然你来算啥(这好像是废话)
3.那我们就愉快的输入两个字符数组a,b喽,并且将他们也转移成长度(这步是干什么的呢)
4.将所需输入的数据以字符数组的形式输入,建立字符数组,建立相应的整数数组,然后一一映射,以此来实现数据的输入,需要注意的是,当实现字符向数字映射时,应该减去相应的ASCII偏移值,即48。(这段是抄的,懒得打字了,以后科普一个算ASCII表小知识)
5.a[lena-i]=a1[i]-48;这步是干什么的呢?如果你认真读了上面的话并且思考了,你就知道是为什么了
6.x表示进位 现在为0.
7.如果还有不懂得和我说我再补充
int main()
{
char a1[1000],b1[1000];
int a[1000],b[1000],c[1000],lena,lenb,lenc,i,x;
memset(a,0,sizeof(a));//
memset(b,0,sizeof(b));
memset(c,0,sizeof(c));
scanf("%s",a1);scanf("%s",b1);//scanf就爆0!
lena=strlen(a1);
lenb=strlen(b1);
for(i=0;i<=lena-1;i++)//‘0’就是48
a[lena-i]=a1[i]-48;
for(i=0;i<=lenb-1;i++)
b[lenb-i]=b1[i]-48;
lenc=1;
x=0;
二.
1....咕咕咕
2.好好想一想
while(lenc<=lena||lenc<=lenb)
{
c[lenc]=a[lenc]+b[lenc]+x;//两数相加
x=c[lenc]/10;//要进的位
c[lenc]%=10;//进位后的数
lenc++;//数据下标加一
}
c[lenc]=x;
if(c[lenc]==0)
lenc--;//处理最高位,因为是逆序,可能会出现00
三.1.反向输出数据。因为我们的加法是将数组反置,然后由左到右想加的,加完后,个数位在左边,所以,需要反向输出(chaode)
cout<<c[i];
cout<<endl;
return 0;
```
高精加告一段落,高精减同理,自己试一试
高精乘 高精除 有空有补充 但%99会咕咕咕...
下面介绍另一种 重载运算符高精度+-
```cpp
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
const int M=100000000,
P=8; //压位
struct bignum
{
int n[5000],l; //n数组存放每个结构体中的"大数",l记录长度。
bignum(){l=1,memset(n,0,sizeof(n));}
//-----------------------------------------------
void init() //输入过程
{
string s;
cin>>s;
int now=0,ct=0,c1=1; //now记录当前是n数组的第几位,ct记录已经读入多少字符了,满八进一,c1是辅助变量,因为我们是倒着读入,所以每次要乘10
for(int i=s.length()-1;i>=0;i--) //从s的长度-1开始
{
n[now]+=(s[i]-'0')*c1;
c1*=10;
ct++;
if(ct==P&&i!=0) // 如果i=0了就没有必要now++;
{
now++;
ct=0;
c1=1;
}
}
l=now+1; //l的长度为now+1;
}
void print()
{
printf("%d",n[l-1]);
for(int i=l-2;i>=0;i--)
printf("%0*d",P,n[i]); //补零输出
printf("\n");
}
//-----------------------------------------------
bignum operator + (bignum x) const //重载加号
{
bignum t=*this;
if(x.l>t.l)t.l=x.l;
for(int i=0;i<t.l;i++)
{
t.n[i]+=x.n[i];
if(t.n[i]>=M)
{
t.n[i+1]+=t.n[i]/M;
t.n[i]%=M;
}
}
return t; // 注意:将t的值返回
}
//------------------------------------------------
bool operator < (bignum x) const //重载小于号
{
bignum t=*this;
if(t.l!=x.l)return t.l<x.l;
for(int i=t.l-1;i>=0;i--)
{
if(t.n[i]!=x.n[i]) return t.n[i]<x.n[i];
}
return 0;
}
bignum operator -(bignum x) const //重载减号
{
bignum t=*this;
if(t<x){printf("-");swap(t,x);}
int jie =0;
for(int i=0;i<t.l;i++)
{
t.n[i]-=x.n[i];
while(t.n[i]<0)
{
t.n[i]+=M;
jie++;
}
t.n[i+1]-=jie;
jie=0;
}
while(!t.n[t.l-1] && t.l>1)t.l--; // 相减后有可能出现前面有0的情况,所以t.l--;
return t;
}
//----------------------------------------------
}a,b,c;
int main()
{
a.init(); //读入字符串a和b
b.init();
c=a+b;
c.print();
c=a-b;
c.print();
c=a*b;
c.print();
return 0;
}
注释咕咕咕