整数相乘的分治算法

来源:互联网 发布:全国网络电视直播 编辑:程序博客网 时间:2024/05/10 16:55
  • 引言
    很久很久以前,有人是这样算乘法的:x*y,好经典~
    有人是这样算复数乘法的:(a+bi)(c+di)=ac-bd+(bc+ad)i,实数乘法进行了四次,这种普通乘法时间复杂度是O(n^2)。
    但是!我们伟大的数学家高斯(Gauss)发现,其实上式可以通过三个实数乘法来完成:ac, bd ,(a+b)(c+d)。
    这种算法可以应用到大数相乘之中,当数小的时候这只是很小的改进,但是当数很大的时候,若递归地应用这个小幅改进,则算法的效率得到极其显著的提升!!

  • 分治算法介绍
    给定两个n位的二进制整数x和y(当然次算法不限定二进制数),作为x乘y的第一步,我们将x和y一分为二,每个数的左半部分和右半部分都是n/2位的二进制整数:
    这里写图片描述
    例如,如果X=10110110B(B表示该数是二进制数),那么XL=1011B, XR=0110B, 同时X=1011B*2^4+0110B. x和y的乘积从而可以写为以下形式:
    这里写图片描述
    看上去我们要进行4次实数乘法(乘2的幂相当于左移运算不考虑),实际上,类似上面引言的介绍,只需要进行三次乘法:XLYL,XRYR,(XL + XR)(YL + YR), 因为XLYR + XRYL = (XL + XR)(YL + YR) - XLYL - XRYR
    运行时间改进为O(n^1.59)。

  • 伪代码
    这里写图片描述
    下面本人写的代码主要也是参照这个伪代码实现,不同的是加了个符号表示数的正负。

  • 函数实现细节(输入x和y,还有它们的位数n,二者等长)
    1.计算x*y的正负
    2.定义变量
    3.判断x和y是否为0,若是0返回0
    4.若x和y位数均为1,则直接返回x*y的结果,不必做分治
    5.计算x和y的各个部分,XL, XR, YL, YR, 注意考虑n为奇数的情况,则分L比R长一位。
    6.计算P1=XLYL,P2=XRYR,P3=(XL + XR)(YL + YR)
    7.返回P1x10^(2*floor(n/2))+(P3-P1-P2)x10^(n/2)+P2(此处对应伪代码的最后一行,本人用了十进制)

  • 完整代码

#include<iostream>#include<cmath>using namespace std;#define SIGN(A) ((A>0)?1:-1)//定义一个符号函数表示正负int multiply(int x, int y,int n){    int sign = SIGN(x)*SIGN(y);    int XR, XL, YR, YL;    int P1, P2, P3;    if (x == 0 || y == 0)        return 0;    if (n == 1)        return x*y;    else    {        //计算X和y的各个部分        XL = x / pow(10, n / 2);        XR = x - XL*(pow(10, n / 2));        YL = y / pow(10, n / 2);        YR = y - YL*(pow(10, n / 2));        //分治计算        P1 = multiply(XL, YL, n-n/2);        P2 = multiply(XR, YR, n / 2);        P3 = multiply(XL + XR, YL + YR, n-n/2);        return sign*(P1*pow(10, 2*floor(n/2)) + (P3 - P1 - P2)*pow(10,n/2) + P2);    }}int main(){    printf("请输入两个等长的数字x和y...\n");    int x, y, n;    printf("请输入x:\n");    cin >> x;    printf("请输入y:\n");    cin >> y;    printf("请输入x和y的位数:\n");    cin >> n;    printf("---------------------------------------------\n");    printf("x * y = ");    cout<<multiply(x, y, n)<<endl;    printf("非分治算法求得 x * y = ");    cout << x*y<<endl;    system("pause");    return 0;}
  • 结果截图
    这里写图片描述
0 0
原创粉丝点击