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++不配了。。。