洛谷 P5703 苹果采购 简单乘法 P1303 A*B Problem 高精度乘法 高精度算法 进位 数据范围 基本运算

P5703是一个超级简单的乘法问题。

一小孩要a个苹果,一共有b个小孩。
问要多少个苹果。

直接:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
	int a,b;
	cin >> a >> b;
	cout << a*b << endl;
    return 0;
}

果然,入门题还是入门题。

和这一个题看似一样的P1303的A*B Problem,把这个代码交上去会有什么神奇的事情发生呢?

作死试试:
意料之中,#1#2AC,#3#4#5WA。
其实A*B Problem是一个初步的高精度乘法,也可以看作是一个例题,一个模板。

高精度:
我们都知道,计算机存储的位数是有限的,向int定义出来的变量,最大只能是0x7fffffff(16进制),或者2147483647(十进制)。

运行一下这个代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
	int a;
	a = 0x7fffffff;
	cout << a; 
    return 0;
}

输出结果:2147483647。很正常。

再运行一下这个:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
	int a;
	a = 0x7fffffff;
	cout << a+1; 
    return 0;
}

运行结果:-2147483648,好像出现了一点问题。没错,这就是int的范围边界了。具体原理,还要从计算机的基础硬件知识开始说起。

简单来说就是int类型的最大值和最小值构成了一个循环,从-2147483648——2147483647。所以就会看到了最大值+1成为了最小值。

重点说一说高精度:

为了避免在存储范围上的限制,运算更大的数值,就必须使用我们的算法来实现(c++中)。

思考一下,怎么存一个很大的数值?
一个方法是,使用数组,一位一位的存储。这是个好办法。
怎么一位一位的输入数组里面去呢?
一个好办法是,使用字符型数组,然后还涉及到字符与数值之间的转换。
再加上存储结果的数组。

说开就开:

char a0[50001],b0[50001];
int a[50001],b[50001],c[50001];

然后输入字符,并转换成数值型。
减去‘0’的ACSLL码就好。
例如 :‘6’-‘0’ = 6

说写就写:

cin >> a0 >> b0;
a[0] = strlen(a0);
b[0] = strlen(b0);
for(i=1;i<=a[0];++i) 
	a[i] = a0[a[0]-i]-'0';
for(i=1;i<=b[0];++i) 
	b[i] = b0[b[0]-i]-'0';

这里有没有注意到,从字符数组转换成数组数组的时候,做了一点简单的处理。

把数据从头到脚反了过来!

这就是高精度乘法独特的算法设计,想一想,咱们列式子算乘法的时候怎么算?

没错,是从低位到高位算。用乘数的每一项,分别乘以第二个乘数的每一项,最后进行竖向的加法。

观察一下,不难得出,乘出来放入c数组的位置和两个乘数都有关系。
具体是a数组的第i个数乘上b数组的第j个数,最后放在c数组的第i+j-1的位置。

即:

for(i=1;i<=a[0];++i)
	for(j=1;j<=b[0];++j)
	{
		c[i+j-1] += a[i]*b[j];
	}

最后处理乘出来的数的加法:
大于十就进位,只剩下个位数。

代码是这样的:

len = a[0]+b[0];
for(i=1;i<len;++i)
	{
		if(c[i]>9)
		{
			c[i+1] += c[i]/10;
			c[i] = c[i]%10;	
		}
	}

我们初步让c的位数为len,len为a数组和b数组长度的加和。

最后,如果进位进不到很大的位数,就会有前面位为0,我们就把前导零去掉。

代码子:

while(c[len]==0&&len>1) len--;

别忘了咱们是倒着算的,当然也要倒着输出:

for(i=len;i>=1;--i)
	cout << c[i];

高精度乘法,完成!

完全代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
char a0[50001],b0[50001];
int a[50001],b[50001],c[50001],len,i,j;
int main()
{
	cin >> a0 >> b0;
	a[0] = strlen(a0);
	b[0] = strlen(b0);
	for(i=1;i<=a[0];++i) a[i] = a0[a[0]-i]-'0';
	for(i=1;i<=b[0];++i) b[i] = b0[b[0]-i]-'0';
	for(i=1;i<=a[0];++i)
	for(j=1;j<=b[0];++j)
	{
		c[i+j-1] += a[i]*b[j];
	}
	len = a[0]+b[0];
	for(i=1;i<len;++i)
	{
		if(c[i]>9)
		{
			c[i+1] += c[i]/10;
			c[i] = c[i]%10;	
		}
	}
	while(c[len]==0&&len>1) len--;
	for(i=len;i>=1;--i)
	cout << c[i];
    return 0;
}

end!

彩蛋:

print(int(input())*int(input()))

嗷呜!Python直接无视高精度。

import java.math.BigDecimal;
import java.util.Scanner;

public class Main {

	public static void main(String[] args) {
		String str1, str2;
		Scanner input = new Scanner(System.in);
		str1 = input.next();
		str2 = input.next();
		BigDecimal b1 = new BigDecimal(str1);
		BigDecimal b2 = new BigDecimal(str2);
		System.out.println(b1.multiply(b2));
		
	}
}

嗷呜,Java直接BigDecimal。

是我C++不配了。。。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

三元湖有大锦鲤

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

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

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

打赏作者

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

抵扣说明:

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

余额充值