高精度乘法和除法(巨详细看懂汉字就能看懂)

高精度乘法

如果有什么意见或者想法,请评论留言,期待你们的提出的建议或纠正。

请现在静下心来,跟着我的思路,很快你就会拿捏它的。

1、首先我们用字符串来存储两个数(因为数比较大),接下来把他们放到整数数组里面,放的时候要倒叙(因为我们平常算乘法的时候我们是从个位数开始算,我们是从第一个下标开始算,不能先算高位是吧,哈哈

2、存储完成之后,我们是不是要开始算乘法了,应该怎么算呢?咱们先看一个图片:
在这里插入图片描述
我来解释一下,我们看第一行,a0,a1,a2代表三个数字,比如123,他们分别是1,2,3。b数组是一样的,接下来a0b0这些就是他们相乘的结果,那么c0,c1这些是他们相加的结果,如a1b0,a0b1相加的结果是c1存到这个数组里面。这里我们可以发现a0b0,a1b0这些下标加起来的数字就是c数组的下标*。**

3、图看懂了基本就没问题了,接下来就是如何实现该图,

4、我们用这个代码可以得到c数组的内容(先把这个代码看懂再接着往下看):

for(int i=0;i<(int)s1.size();i++)
	{
		for(int j=0;j<(int)s2.size();j++)
		{
			c[i+j]+=a[i]*b[j];
		}
	}

5、我们现在就要对c数组进行处理了,其实就是高精度加法的步骤,不会高精度加法的小伙伴可以看我前面的作品,也是超详细的。

6、这里有个结论就是算的结果的长度是不会大于前面输进来的两个数的总长度的。

7、再看这个代码:

int lc=(int)s1.size()+(int)s2.size();这个就是6中所说的内容
for(int i=0;i<lc;i++)这个是高精度加法,其实就是进位,超过10的话我们要进位。
	{
		if(c[i]>9)10
		{
			c[i+1]+=c[i]/10;进位
			c[i]%=10;自身得到的是个位
		}
	}

8、我们对c数组处理完了之后,就是除去多余的0了(因为结果的长度不一定大于最大长度)。
9、代码是:

	for(lc;c[lc]==0;lc--);除去多余的0,咱们要倒叙输出,开的数组又大,必须要除0for(lc;lc>=0;lc--)		cout<<c[lc];

可以参考我的整体代码:

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int a[10001]={0},b[10001]={0},c[10001]={0};
	string s1,s2;
	cin>>s1>>s2;
	for(int i=0;i<(int)s1.size();i++)	a[s1.size()-i-1]=s1[i]-'0';
	for(int i=0;i<(int)s2.size();i++)	b[s2.size()-i-1]=s2[i]-'0';
	int lc=(int)s1.size()+(int)s2.size();//加的结果的长度不会超过这个数
	for(int i=0;i<(int)s1.size();i++)
	{
		for(int j=0;j<(int)s2.size();j++)
		{
			c[i+j]+=a[i]*b[j];
		}
	}
	for(int i=0;i<lc;i++)
	{
		if(c[i]>9)
		{
			c[i+1]+=c[i]/10;
			c[i]%=10;
		}
	}
	if(s1=="0"||s2=="0")有一个数是0结果是0
	{
		cout<<0;
		return 0;
	}
	for(lc;c[lc]==0;lc--);
	for(lc;lc>=0;lc--)		cout<<c[lc];
	return 0;
}

高精度除法

第一种是高精度除以低精度

1、我们只需要存储一个大数就行,这个算除法的时候和我们平常一样,这个就不需要倒序了。
我们先看一个图理解主要思路吧!(图可能有点丑哈哈)
现在
现在跟着我的思路来理解吧,慢慢来首先我们是2除以13得0余2,然后把余数乘以10再加上下一位数3得23,再进行让23除以13得1余10,接着把余数10乘以10加上下一个数4得104,再往后拿着104除以13得8余0,再接着把余数0乘以10加上下一个数5得5,最后拿着5除以13得0余5结束。

2、我们要把这个步骤换成代码是这样的:

	int x=0;	注意这个变量
	for(int i=0;i<len;i++)注意这里的b就是上面的13,a数组里面存放的是2345
	{
		c[i]=(x*10+a[i])/b;核心代码,这个就是除一下得到商,逐位开始除
		x=(x*10+a[i])%b;这个就是每除以一次得到的余数。如果这里实在看不懂的话你可以拿着笔一步一步写一遍,或许就知道了呢。
	}

3、最后我们就把前面的多余的0去掉,这里去掉的就是上面的180左边的0。
可以参考整体代码:

#include<bits/stdc++.h>
using namespace std;

int main()
{
		int a[201]={0},c[201]={0},b,x=0;
		string s;
		cin>>s>>b;
		int len=s.size();
		for(int i=0;i<len;i++)	a[i]=s[i]-'0';
		for(int i=0;i<len;i++)
		{
			c[i]=(x*10+a[i])/b;
			x=(x*10+a[i])%b;
		}
		int m=0;
		for(m=0;c[m]==0;m++);
		for(m;m<len;m++)	cout<<c[m];	
	return 0;
}

第二种就是高精度除以高精度

我们还是先了解一下思路吧!咱们直接上图:
静下心来把这个图搞懂它。
在这里插入图片描述
我来解释一下这个图片。慢慢读这段话:首先这里用的是531518除以123,在刚开始我们要让123这个数的位数和我们要除的数的位数一致,因为我们是用减法一直减到531518小于123000这个数,在这个过程中我们减了多少次就相当于拿着123000乘以这个次数,你看123000乘以次数4是492000。这个4是不是就是相当于我们要得到商的最高位数上的数字。接下来我们要更新123了,因为我们还是要重复上面的步骤。把123变成12300才可以减的。再减到39518比12300小结束这个循环,再更新123为1230,一直减到2618比1230小,到什么时候结束呢?到减的数比123小结束。

1、上面的图你懂了,基本就懂了核心了。

2、我们还是要输入两个字符串,再把每个字符变为数字倒序放到数组里面(这个原因上面说过了,这里就不用多说了吧,不会的小伙伴往上面看哦,在最上面那里),我们这个存放要稍微变动一下,我们数组的第一个位置上放这个数的长度,在数组第二个位置上开始放数字。这里有个结论:按照上面531518除以123的例子说,商的最大长度不能大于531518的位数减去123的位数+1,可以比它小

3、我们这里最大的商的位数是4,你看当我们要求出最高位第四位上的数的时候,是不是在123后面添加了3个0,当我们要求出第三位上的数字的时候,是不是要在123后面加上2个0,同理第二位上时是不是加上1个0。我们就可以的出这个结论,求第i位上的数的时候在我们这里的123后面加上i-1个0.

在这上面理解完之后,我们来看代码怎么实现的吧!
静心看,我觉得算详细了吧!如果还有不懂,请评论留言,我会很快回复的。

#include<bits/stdc++.h>
using namespace std;
int a[201]={0},b[201]={0},c[201]={0},tmp[201]={0},len=0;
string s1,s2;
int comp(int a[],int b[])  *****这个函数是用来比较两个数的大小的
{
	if(a[0]>b[0])	return 1; *****如果a数组里的数位数比b的大那么就是,它大直接结束
	if(a[0]<b[0])	return -1; *****这个就是存放在b数组里的数比较大
	for(int i=a[0];i>0;i--)  *****这里是来讨论两个数的位数相同时,逐一比较,相同位数上的数大,那么这个数就大。
	{
		if(a[i]>b[i])	return 1;
		else 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]大就代表减不了了,就要向前一位借一
		{
			a[i+1]-=1;  *****这里就是借1 
			a[i]+=10;   *****借完1了自身肯定是要加10的,这个原理就是我们平常算的减法
		}
		a[i]=a[i]-b[i];  *****这里是我们减完数了之后,把a数组更新成减完的数。
	}
	while(a[a[0]]==0&&a[0]>0)
	{
		a[0]--;  *****这里就是算更新完了的a数组的位数,位数也可能会更新的。
	}
}
void numcopy(int p[],int q[],int n) *****这里就是把上面的那个123后面加上n-10。是上面3结论里的内容
{
	for(int i=1;i<=p[0];i++)	*****q[i+n-1]=p[i]; (因为我初始化的时候,数组里面的数是0,所以空余位上都是0,相当于后移完了之后,前面的数加上了0)将数组里的数逐个后移n-1位
	q[0]=p[0]+n-1;  *****移动了多少位,在q[0]里面写上更新后的位数
}
int main()
{
	getline(cin,s1);   *****输入数据
	getline(cin,s2);
	a[0]=(int)s1.size(),b[0]=(int)s2.size();  *****存放位数
	for(int i=0;i<(int)s1.size();i++)		a[a[0]-i]=s1[i]-'0';  *****倒叙存放,第一个位置是位数,不存别的
	for(int i=0;i<(int)s2.size();i++)		b[b[0]-i]=s2[i]-'0';
	c[0]=a[0]-b[0]+1; *****商的最大长度
	for(int i=1;i<=c[0];i++)
	{
		memset(tmp,0,sizeof(tmp));*****将tmp数组初始化
		numcopy(b,tmp,i);*****更新b数组,后面要加上i-10
		while(comp(a,b)>=0)
		{
			c[i]++;*****记录上的第i位上的数字,减一次那个数字就加一次
			minu(a,b);*****做减法
		}
	}
	int k;
	for(k=c[0];c[k]==0;k--);*****去除多余的0
	for(k;k>0;k--)	cout<<c[k];
	return 0;
}

希望能帮到你!上面的可能有点不太好看,下次我会不断进步的,一起努力!
有什么意见尽管提,我会改进的,期待你的意见!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值