时间:2014.04.19
地点:基地二楼
-------------------------------------------------------------------------
某些应用,需要对超过100位的十进制整数进行乘法运算,比如在密码技术当中,这样因为整数过于的长,计算机的一个字也装不下这样的长度整数,于是要做特别的处理,况且乘法的效率上也想要有所提高。显然我们通常的笔算乘法时间复杂度为平方级别的。我们想构建一个小于平方级别的算法。
-------------------------------------------------------------------------
先看一个两位数的乘法例子:23*14
23=2*10^1+3*10^0;
14=1*10^1+4*10^0;
23*14=(2*1)10^2+(2*1+3*4)10^1+(3*4)10^0
在这里2*1和3*4是不可避免的,然后利用它们两我们使用一次乘法就可计算出中间值。现在我们来总结一条规律:
对于任何两位数a=a1a0和b=b1b0,它们的乘积c可以这样计算:
c=ab=c2 * 10^2 + c1 * 10^1 +c0
其中 c2=a1*b1 c0=a0 *b0 c1=(a1+a0)(b1+b0)-(c2+c0)
现在,假设有两个n位整数a和b,如果没有,我们就根据最长的补齐n位数,且假设n为偶数,我们可以把数一分为二,把a的前半部分记为a1,后半部分记为a0,对b也做类似的处理,前半部分叫b1,后半部分叫b0。于是有:
a=a1 * 10^(n/2) +a0 b=b1 * 10^(n/2) + b0
那么和处理两位数一样,我们可以类似的得到:
c=ab=c2 * 10^n + c1 * 1 0^ (n/2) +c0
其中,c2=a1*b1 c0=a0*b0 c1=(a1+a0)(b1+b0)-(c2+c0)
即中间部分是a的两部分和与b的两部分和的积减去c2与c0的和。
-------------------------------------------------------------------------
在大数乘法的实现中,一是要注意n必须为偶数,当然如果n是2的幂,那么狠好办,一直递归下去,直到n=1时直接返回值,但很多时候,这样做很浪费,我们只要每次递归检查数的位数然后补齐为偶数位即可。还有一个小问题是在获得数据的位数时,刚开始我是用除10的方法得到的,在一个while循环里,但某次检查我发现程序出错,原因是当到了传进去的数字为0时,它不会返回的数位为0,找这个错找了好久,数字o的位数应该是为1,所以修改后应该在一个do...while循环中进行。源码如下:
#include<iostream> using namespace std; int IntegerLength(long long data) { int size = 0; do { data /= 10; ++size; } while (data); return size; } long long BigDataMultiply(long long a, long long b) { size_t a_length, b_length; a_length = IntegerLength(a); b_length = IntegerLength(b); size_t size = (a_length >= b_length) ? a_length : b_length; if (size == 1) return a*b; else { if (size % 2 != 0) size += 1; long long partion_data = static_cast<int>(pow(10, size / 2)); long long a1 = a / partion_data; long long b1 = b / partion_data; long long a0 = a%partion_data; long long b0 = b%partion_data; long long c2 = BigDataMultiply(a1, b1); long long c0 = BigDataMultiply(a0, b0); long long c1 = BigDataMultiply((a1 + a0),(b1 + b0)) - (c2 + c0); long long c = c2*partion_data*partion_data + c1*partion_data + c0; return c; } } int main() { long long a, b; cin >> a >> b; cout << BigDataMultiply(a, b) << endl; return EXIT_SUCCESS; }
-------------------------------------------------------------------------
这个算法相比笔算法的平方级时间复杂度已经下降到n的1.585,已经得到了很大的改进。
原文:http://blog.csdn.net/u012333003/article/details/24133427