对于32位字长的机器,大约超过20亿,用int类型就无法表示了,我们可以选择int64类型,但无论怎样扩展,固定的整数类型总是有表达的极限!如果对超级大整数进行精确运算呢?一个简单的办法是:仅仅使用现有类型,但是把大整数的运算化解为若干小整数的运算,即所谓:“分块法”。
上图表示了分块乘法的原理。可以把大数分成多段(此处为2段)小数,然后用小数的多次运算组合表示一个大数。可以根据int的承载能力规定小块的大小,比如要把int分成2段,则小块可取10000为上限值。注意,小块在进行纵向累加后,需要进行进位校正。
请从以下四个选项中选择正确答案,填补在空白处,使得代码能运行后能产生正确的结果。
最终代码如下
#include <bits/stdc++.h> using namespace std; void bigmul(int x, int y, int r[]) { int base = 10000; int x2 = x / base; int x1 = x % base; int y2 = y / base; int y1 = y % base; int n1 = x1 * y1; int n2 = x1 * y2; int n3 = x2 * y1; int n4 = x2 * y2; r[3] = n1 % base; r[2] = n1 / base + n2 % base + n3 % base; r[1] = n2 / base + n3 / base + n4 % base; r[0] = n4 / base; r[1] += r[2] / base; r[2] = r[2] % base; r[0] += r[1] / base; r[1] = r[1] % base; } int main(int argc, char *argv[]) { int x[] = {0, 0, 0, 0}; bigmul(87654321, 12345678, x); printf("%d%d%d%d\n", x[0], x[1], x[2], x[3]); return 0; }
这次的练习相对偏中等难度,其实很多时候,都是理念问题,思路对了解起来就容易。下面上解析。
解题思路
1. 获取x1,x2,y1,y2
int base = 10000; int x2 = x / base; int x1 = x % base; int y2 = y / base; int y1 = y % base;
这里有个大前提啊同学们,输入的整数x和y必须是大整数,10000以上的吧,要不然没有意义。
正常我们是十进制,这里按照10000进制,将大整数拆分成两个小一点的整数。
2.计算x1*y1,x1*y1,x2*y1,x2*y2的值
int n1 = x1 * y1; int n2 = x1 * y2; int n3 = x2 * y1; int n4 = x2 * y2;
分别是n1,n2,n3,n4,从上到下。
3.竖列相加
1. r[3] = n1 % base; r[2] = n1 / base + n2 % base + n3 % base; r[1] = n2 / base + n3 / base + n4 % base; r[0] = n4 / base;
题目中是r1~r4,但是我们数组中是从0开始的,所以是r0~r3,大家知道怎么回事就行,别自己搞乱了。备注:特别容易搞乱,注意r1和r[1],带不带方括号很重要,r1=r[0].
这里的数字采用数组进行存储:
看图可知,r4=r[3]是n1后面一位,按照咱们认为的10000进制,那么r[3]=n1 % base,就是个整除取余。
看图可知,r3=r[2]是n1前一位加上n2和n3的后一位,那么r[2]=n1 / base + n2 % base + n3 % base。
看图可知,r2=r[1]是n2和n3的前一位加上n4后一位,那么r[2]=n2 / base + n3 / base + n4 % base。
看图可知,r1=r[0]是n4的前一位,那么r[0]=n4 / base。
4.进位
r[1] += r[2] / base; r[2] = r[2] % base; r[0] += r[1] / base; r[1] = r[1] % base;
还是把这个图拿过来了,方便看,另外,先不要看上面的代码,先看博主分析:
r4=r[3]就不说了,m1本身就是n1 % base之后的值,不需要进位。
r3=r[2]不知道要不要进位,所以需要整除取余,不需要进位,就是本身,需要进位,取余之后的值就是r3,即r[2].
r2 = r[1]也不知道要不要进位,算就完了,所以r[1] = r[1] + r[2] / base。我们就假设r3要进位,那就要加上进位的数,r3 / base就是这个数,有的话就是个大于0的值,没有的话就是0。
r1 = r[0]也不知道要不要进位,同样的,算就完了,和上面的一样,r[0]=r[0]+r[1]/base。都是先假设r2有进位,加上进位的数,r2 / base就是这个数,有的话就是个大于0的值,没有的话就是0。
最后你发现代码和上面的不一样,对不对?那就对了,需要注意什么呢?
r[1] = r[1] + r[2] / base之后,r[1]是不是也有进位的可能,所以r[1]要接着取余,r[1] = r[1] % base。
r[0]已经是第一位了,没有取余的必要了,现在,代码和上面的一样了。
5.最终运算
在main函数中调用bigmul,传入参数,然后直接按顺序不换行输出x[0], x[1], x[2], x[3],连起来就是两个大整数想成的积。
总结
再次感叹数学的伟大,大学时高数里可也是没有学过这样的公式运算,抑或是学过我忘了?真是没有一点印象,有句话叫:世上的一切问题都可以用数学解决。真是越看越心惊,我这里写完了,不知道大家都看懂没,欢迎评论区留言讨论。