高精度算法

目录

1:高精度加法

2:高精度减法

3:高精度乘法

4:高精度除法


对于高精度算法的理解,算法中我们一般会遇到非常大的数,long long类型最多只能支持10的18次方,再大的话就溢出了,这时候我们就需要高精度算法了,高精度算法不管是加减乘除我们用到的思路都是字符串的做法,具体就是,把之前要需要操作的数一个一个的提取出来放到数组中,然后再分别进行加减乘除,具体的操作我们来看下面。


1:高精度加法

for(int i=1;i<=lc;i++){
  c[i]+=a[i]+b[i];
  c[i+1]=c[i]%10;
  d[i]=c[i]%10;
}
//按照数学中的加法的方法就可以想出来啦
   如:1 9 3
     + 2 3 1

a数组: 3  9  1
b数组: 1  3  2

从i=1开始,到i=lc结束

i=1:
c[1]+=a[1]+b[1]=4;
c[2]=c[1]/10=4/10=0;
c[1]=c[1]%10=4
所以c[1]=4

i=2:
c[2]+=a[2]+b[2]=12;
c[3]=c[2]/10=1;
c[2]=c[2]%10=2;
所以c[2]=2

i=3:
c[3]+=a[3]+b[3]=1+1+2=4;
c[4]=c[3]/10=4/10=0;
c[3]=c[3]%10=4
所以c[3]=4

输出是从后往前的
所以答案是424
#include<bits/stdc++.h>
using namespace std;
char sa[2200],sb[2200];
int la,lb,lc,a[2200],b[2200],c[2200];
int main()
{
	scanf("%s",sa);
	scanf("%s",sb);
	la=strlen(sa);
	lb=strlen(sb);
	lc=max(la,lb)+1;
	//开始将字符串中的数字转换成整型并且将他们一个一个的分配到数组中
	for(int i=1;i<=la;i++){
		a[i]=sa[la-i]-'0';
	}
	for(int i=1;i<=lb;i++){
		b[i]=sb[lb-i]-'0';
	}
	//开始模拟数组每个位数上的加法,一个一个进行模拟
	for(int i=1;i<=lc;i++){
		c[i]+=a[i]+b[i];
		c[i+1]=c[i]/10;
		c[i]=c[i]%10;
	}
	//while的原因是防止首部出现0,即出现前导0;
	while(c[lc]==0&&lc>1)lc--;
	for(int i=lc;i>0;i--)cout<<c[i];
	return 0;
}

2:高精度减法

for(int i=1;i<=lc;i++)
{
  if(a[i]<b[i]){
      a[i+1]--;
      a[i]+=10;
    }
   c[i]=a[i]-b[i];
}


假如
sa数组:1 2 3
sb数组:2 1 4

反过来的
a数组: 3 2 1
b数组:4 1 2

那么根据下面的com函数判断可知b数组更大,所以输出要加负号,同时将a数组和b数组互换
所以还是大的减小的,只是加了个符号而已

那就是
a: 4 1 2
b: 3 2 1

从i=1开始
a[1]>b[1],不需要借数,直接减
c[1]=a[1]-b[1]=1

i=2
a[2]<b[2]
需要借数,那么,a[3]就要减一,同时a[2]借到了,就要加个10,理由就是减法的规则,个位数减不够,向十位借,个位不就加10了吗。
那现在是
a[2]=10+a[2]=11
a[3]--
a[3]=1
c[2]=a[2]-b[2]=11-2=9

i=3
a[3]=1
b[3]=1 
c[3]=a[3]-b[3]=0

最后记得还是反着输出的哦,还有符号的哦
-91

 

#include<bits/stdc++.h>
using namespace std;
char sa[2200],sb[2200],sc[2200];
int a[2200],b[2200],c[2200];

bool com(char aa[],char bb[])
{
	//判断sa和sb哪个更加大,sb大则返回false;
	int la=strlen(aa),lb=strlen(bb);
	if(la>lb)return false;
	else if(la<lb)return true;
	for(int i=0;i<la&&i<lb;i++){
		if(aa[i]>bb[i])return false;
		if(aa[i]<bb[i])return true; 
	}
	return false;
}
int main()
{
	scanf("%s",&sa);
	scanf("%s",&sb);
	int f=0;//判断那个更加大
	if(com(sa,sb)){
		//如果sb更大的话,那么就要加个负号,并且两个数组换一下
		f=1;
		strcpy(sc,sa);
		strcpy(sa,sb);
		strcpy(sb,sc);
	}
	int la=strlen(sa),lb=strlen(sb);
	int lc=max(la,lb)+1;
	for(int i=1;i<=la;i++){
		a[i]=sa[la-i]-'0';
	}
	for(int i=1;i<=lb;i++){
		b[i]=sb[lb-i]-'0';
	}
	for(int i=1;i<=lc;i++){
		if(a[i]<b[i]){
			a[i+1]--;
			a[i]+=10;
		}
		c[i]=a[i]-b[i];
	}
	while(c[lc]==0&&lc>1)lc--;
	if(f==1)cout<<"-";
	for(int i=lc;i>0;i--)cout<<c[i];
	return 0;
}

3:高精度乘法

核心思想以及代码

for(int i=1;i<=la;i++){
 for(int j=1;j<=lb;j++){
   c[i+j-1]+=a[i]*b[j];
   c[i+j]+=c[i+j-1]/10;
   c[i+j-1]=c[i+j-1]%10;
 }
}

什么意思呢?举个例子
   1 2 3
  *  2 1
————————————
   1 2 3
 2 4 6
————————————
 2 5 8 3
和下面的对比下
         a3   a2    a1
       *      b2    b1
    _____________________
         a3b1 a2b1 a1b1
    b2a3 b2a2 b2a1
    _____________________
 
位置:  4     3     2   1 

发现了规律没有好像都是i+j-1的位置哦
那么接下来就不用我多说了吧(哈哈哈)

 

#include<bits/stdc++.h>
using namespace std;
char sa[2200],sb[2200],sc[2200];
int a[2200],b[2200],c[2200];

int main()
{
	scanf("%s",&sa);
	scanf("%s",&sb);
	int la=strlen(sa),lb=strlen(sb),lc;
	for(int i=1;i<=la;i++){
		a[i]=sa[la-i]-'0';
	}
	for(int i=1;i<=lb;i++){
		b[i]=sb[lb-i]-'0';
	}
	
	for(int i=1;i<=la;i++){
		for(int j=1;j<=lb;j++){
			c[i+j-1]+=a[i]*b[j];
			c[i+j]+=c[i+j-1]/10;
			c[i+j-1]=c[i+j-1]%10;
		}
	}
	lc=la+lb;
	while(c[lc]==0&&lc>1)lc--;
	for(int i=lc;i>0;i--)cout<<c[i];
	return 0;
}

4:高精度除法

高精度除法是分情况的,分高精度除以低精度,高精度除以高精度,这个意思,应该很明确吧,我就不用多说了吧。不就是数位吗(对蛮,哈哈哈)

(1)高精度除以低精度

核心思想以及代码展现:
 
for(int i=1;i<=la;i++){
 c[i]=(x*10+a[i])/b;
 x=(x*10+a[i])%b;
}


嗯...怎么说呢,举个例子吧
比如说588除以28的例子吧
这里我用a/b表示哈(就是懒呗)
 一般正常的除法运算
588/28,588的百位十位是58,58除以28是2,但还余2,然后
588的个位下来,和余的数2组合成了28,28/28是1,所以答案
是21。


大家有发现什么规律吗,对!!!重点是如果不是整除而有余数的
话,都需要用到后面一位的数,这就是上面代码中的x了,不够就乘10,
一个不够,c[i]上填个0,x继续扩大十倍。这样最后就可以出现答案了。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
char sa[22000];
ll b,x,c[22000],a[22000];

int main()
{
	scanf("%s",&sa);
	cin>>b;
	int la=strlen(sa),lc;
	for(int i=1;i<=la;i++){
		a[i]=sa[i-1]-'0';//注意哦,这里跟前面的高精度加减不一样哦,不是从后的哦
	}
	for(int i=1;i<=la;i++){
		c[i]=(x*10+a[i])/b;
		x=(x*10+a[i])%b;//这里就是除法的基本知识,用草稿本多做几次模拟体验一下哦
	}
	lc=1;
	while(c[lc]==0&&lc<la)lc++;
	for(int i=lc;i<=la;i++)cout<<c[i];
}

(2)高精度除以高精度

核心思想:
这里用到的是减法模拟法来做
这里的减法是高精度减法哦!!!

举个例子吧
如:
    40728除以28吧
看过程哦:

第一个:
 40728
-28000
_______
 12728
第一个除数大于了被除数,结束,减了一次,记录下来  c[1]=1

第二个

 12728
- 2800
_______
  9928
- 2800
_______
  7128
- 2800
_______
  4328
- 2800
_______
  1528
1528<2800结束循环,减了4次,记录下来,c[2]=4

第三个:
 1528
- 280
————————
 1248
- 280
————————
  968
- 280
————————
  688
- 280
————————
  408
- 280
————————
  128

118<280,结束循环,减了5次,记录下来,c[3]=5

第四个:
 128
- 28
——————
 100
- 28
——————
  72
- 28
——————
  44
- 28
——————
  16
16<28,结束循环,减了4次,记录下来,c[4]=4
到后面已经没有什么28的倍数可以和16相减了,所以到此结束,并且余数就是16

说以答案是1454余16  

#include<bits/stdc++.h>
using namespace std;
char sa[305],sb[300];
int a[1000],b[1000],c[1000],tmp[1000];
void print(int a[])
{
	if(a[0]==0){
		cout<<0;
		return ;
	}
	for(int i=a[0];i>0;i--)cout<<a[i];
	return ;
}
int compare(int a[],int b[])//返回1表示a>b
{
  if(a[0]>b[0])return 1;
  if(a[0]<b[0])return -1;
  for(int i=a[0];i>0;i--){
  	if(a[i]>b[i])return 1;
  	if(a[i]<b[i])return -1;
  }	
  return 0;
}	
void minu(int a[],int b[])
{
	//做减法
	for(int i=1;i<=a[0];i++){
		if(a[i]<b[i]){
			a[i+1]--;
			a[i]=a[i]+10;
		}
		a[i]=a[i]-b[i];
	}
	while(a[a[0]]==0&&a[0]>0)a[0]--;
}
void numcpy(int p[],int q[],int n)
{
	//将p数组整体移动n位到q数组中
	for(int i=1;i<=p[0];i++){
		q[i+n-1]=p[i];
	}
	q[0]=p[0]+n-1;
}
int main()
{
	scanf("%s",&sa);
	scanf("%s",&sb);
	a[0]=strlen(sa);//这里数组的0下标表示的都是该数组的长度,这样做的原因是为了节省空间
	b[0]=strlen(sb);
	for(int i=1;i<=a[0];i++){
		a[i]=sa[a[0]-i]-'0';
	}
	for(int i=1;i<=b[0];i++){
		b[i]=sb[b[0]-i]-'0';
	}
	c[0]=a[0]-b[0]+1;
	for(int i=c[0];i>=1;i--){
		memset(tmp,0,sizeof(tmp));
		numcpy(b,tmp,i);//b数组整体移动i位到tmp数组中
		while(compare(a,tmp)>=0){
			c[i]++;
			minu(a,tmp);//高精度减法
		}
	}
	while(c[c[0]]==0&&c[0]>0)c[0]--;
    cout<<"商=";
	print(c);
	cout<<endl<<"余数=";
	print(a);
	return 0;
}

 

OK!!!本文到此结束,如有错误,还请大佬指正!!!

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

菜到极致就是渣

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值