【分治】大整数乘法(C++)

  • 刚发现个问题,,初学时竟然是使用的long型进行计算的,导致这篇文章虽展现了分治的想法,但并没有实际解决大整数乘法的计算问题。
  • 仅供参考,日后再改

一、大整数乘法

  1. 一般计算方法
    • 有n位大整数X和Y,计算XY:将Y的每一位与X相乘再按位相加;
    • 时间复杂度:我们需要进行一次n位的乘法,即 T ( n ) = o ( n 2 ) T(n)=o(n^2) T(n)=o(n2)
  2. 分治法(理想状态下)
    • 理想状态:假设有n位大整数X和Y(X和Y位数n相同且为偶数),计算XY。

    • 分治:我们将X、Y分别拆分为a与b、c与d, X = a ∗ 1 0 ⌊ n / 2 ⌋ + b X=a*10^{\left \lfloor n/2 \right \rfloor}+b X=a10n/2+b Y = c ∗ 1 0 ⌊ n / 2 ⌋ + d Y=c*10^{\left \lfloor n/2 \right \rfloor}+d Y=c10n/2+d
      再计算:
      X Y = a c ∗ 1 0 2 ⌊ n / 2 ⌋ + ( a d + b c ) ∗ 1 0 ⌊ n / 2 ⌋ + b d XY=ac*10^{2{\left \lfloor n/2 \right \rfloor}}+(ad+bc)*10^{\left \lfloor n/2 \right \rfloor}+bd XY=ac102n/2+(ad+bc)10n/2+bd

    • 时间复杂度:一共需要进行4次n/2的乘法(ac,ad,bc、bd各一次)和3次加法,
        因而 T ( n ) = 4 T ( n / 2 ) + θ ( n ) = o ( n 2 ) T(n)=4T(n/2)+\theta(n)=o(n^2) T(n)=4T(n/2)+θ(n)=o(n2)

    • 改善:设 E = a c , F = b d , G = ( a − b ) ∗ ( d − c ) = a d − b d − a c + b c E=ac,F=bd,G=(a-b)*(d-c)=ad-bd-ac+bc E=acF=bdG=(ab)(dc)=adbdac+bc,则
      X Y = E ∗ 1 0 2 ⌊ n / 2 ⌋ + ( G + E + F ) ∗ 1 0 ⌊ n / 2 ⌋ + F XY=E*10^{2{\left \lfloor n/2 \right \rfloor}}+(G+E+F)*10^{\left \lfloor n/2 \right \rfloor}+F XY=E102n/2+(G+E+F)10n/2+F

    • 改善后的时间复杂度:一共需要进行3次n/2的乘法(E,F,G各一次)和4次加法,
        因而 T ( n ) = 3 T ( n / 2 ) + θ ( n ) = o ( n 1.59 ) T(n)=3T(n/2)+\theta(n)=o(n^{1.59}) T(n)=3T(n/2)+θ(n)=o(n1.59)

  3. 分治法(非理想状态下)
    • 非理想状态:假设有 n x n_x nx位大整数X和 n y n_y ny位大整数Y(X和Y位数n大小随机),计算XY。

    • 分治:我们将X、Y分别拆分为a与b、c与d, X = a ∗ 1 0 ⌊ n x / 2 ⌋ + b X=a*10^{\left \lfloor n_x/2 \right \rfloor}+b X=a10nx/2+b Y = c ∗ 1 0 ⌊ n y / 2 ⌋ + d Y=c*10^{\left \lfloor n_y/2 \right \rfloor}+d Y=c10ny/2+d
      再计算:
      X Y = a c ∗ 1 0 ⌊ n x / 2 ⌋ + ⌊ n y / 2 ⌋ + ( a d ∗ 1 0 ⌊ n x / 2 ⌋ + b c ∗ 1 0 ⌊ n y / 2 ⌋ ) + b d XY=ac*10^{{\left \lfloor n_x/2 \right \rfloor}+{\left \lfloor n_y/2 \right \rfloor}}+(ad*10^{\left \lfloor n_x/2 \right \rfloor}+bc*10^{\left \lfloor n_y/2 \right \rfloor})+bd XY=ac10nx/2+ny/2+(ad10nx/2+bc10ny/2)+bd

    • 时间复杂度:一共需要进行4次 n x / 2 n_x/2 nx/2 n y / 2 n_y/2 ny/2的乘法和3次加法,
        因而 T ( n ) = . . . T(n)=... T(n)=...

    • 改善:设 E = a c , F = b d , G = ( a ∗ 1 0 n x / 2 − b ) ∗ ( d − c ∗ 1 0 n y / 2 ) E=ac,F=bd,G=(a*10^{n_x/2}-b)*(d-c*10^{n_y/2}) E=acF=bdG=(a10nx/2b)(dc10ny/2),则
      X Y = E ∗ 1 0 ⌊ n x / 2 ⌋ + ⌊ n y / 2 ⌋ + ( G + E ∗ 1 0 ⌊ n x / 2 ⌋ + ⌊ n y / 2 ⌋ + F ) + F XY=E*10^{{\left \lfloor n_x/2 \right \rfloor}+{\left \lfloor n_y/2 \right \rfloor}}+(G+E*10^{{\left \lfloor n_x/2 \right \rfloor}+{\left \lfloor n_y/2 \right \rfloor}}+F)+F XY=E10nx/2+ny/2+(G+E10nx/2+ny/2+F)+F

    • 改善后的时间复杂度:一共需要进行3次 n x / 2 n_x/2 nx/2 n y / 2 n_y/2 ny/2的乘法和4次加法,
        因而 T ( n ) = . . . T(n)=... T(n)=...

二、递归算法实现

1. 设计递归方程

  1. 理想状态下;
    X Y = E ∗ 1 0 2 ⌊ n / 2 ⌋ + ( G + E + F ) ∗ 1 0 ⌊ n / 2 ⌋ + F XY=E*10^{2{\left \lfloor n/2 \right \rfloor}}+(G+E+F)*10^{\left \lfloor n/2 \right \rfloor}+F XY=E102n/2+(G+E+F)10n/2+F
  2. 非理想状态下;
    X Y = E ∗ 1 0 ⌊ n x / 2 ⌋ + ⌊ n y / 2 ⌋ + ( G + E ∗ 1 0 ⌊ n x / 2 ⌋ + ⌊ n y / 2 ⌋ + F ) + F XY=E*10^{{\left \lfloor n_x/2 \right \rfloor}+{\left \lfloor n_y/2 \right \rfloor}}+(G+E*10^{{\left \lfloor n_x/2 \right \rfloor}+{\left \lfloor n_y/2 \right \rfloor}}+F)+F XY=E10nx/2+ny/2+(G+E10nx/2+ny/2+F)+F
  3. 当拆分后的子整数的位数为1时,结束递归。

2. 编写程序代码

  1. 理想状态下;
// 大整数乘法--理想状态
#include <iostream>
#include <cmath>

using namespace std;

int SIGN(long A);
long bigIntMultiply_Ideal(long X, long Y, int n);

int main()
{
    long X = 0;
    long Y = 0;
    int n = 0;

    cout << "大整数乘法:请输入两个大整数:\n";
    cout << "X=";
    cin >> X;
    cout << "Y=";
    cin >> Y;
    cout << "请输入两个大整数的长度:n=";
    cin >> n;

    cout << "\nX*Y=" << bigIntMultiply_Ideal(X, Y, n) << endl;

    return 0;
}

int SIGN(long A)
{
    return A > 0 ? 1 : -1;
}

long bigIntMultiply_Ideal(long X, long Y, int n)
{
    // a-b和d-c可能为负值
    int sign = SIGN(X) * SIGN(Y);
    X = abs(X);
    Y = abs(Y);
    
    if (X == 0 || Y == 0)
        return 0;
    else if (n == 1)
        return sign * X * Y;
    else
    {
        long a = (long)(X / pow(10, n / 2));
        long b = (X % (long)pow(10, n / 2));
        long c = (long)(Y / pow(10, n / 2));
        long d = (Y % (long)pow(10, n / 2));

        long E = bigIntMultiply_Ideal(a, c, n / 2);             // E=a*c
        long F = bigIntMultiply_Ideal(b, d, n / 2);             // F=b*d
        long G = bigIntMultiply_Ideal((a - b), (d - c), n / 2) + E + F; // G=(a-b)*(d-c)+bd+ac

        return (long)(sign * (E * pow(10, n) + G * pow(10, n / 2) + F));
    }
}
  1. 非理想状态下;
// 大整数乘法--非理想状态
#include <iostream>
#include <cmath>

using namespace std;

int SIGN(long A);
long bigIntMultiply_Nonideal(long X, long Y, int n_x, int n_y);

int main()
{
    long X = 0;
    long Y = 0;
    int n_x = 0;
    int n_y = 0;

    cout << "大整数乘法:请输入两个大整数:\n";
    cout << "X=";
    cin >> X;
    cout << "Y=";
    cin >> Y;
    cout << "请输入大整数X的长度:n_x=";
    cin >> n_x;
    cout << "请输入大整数Y的长度:n_y=";
    cin >> n_y;

    cout << "\nX*Y=" << bigIntMultiply_Nonideal(X, Y, n_x, n_y) << endl;

    return 0;
}

int SIGN(long A)
{
    return A > 0 ? 1 : -1;
}

long bigIntMultiply_Nonideal(long X, long Y, int n_x, int n_y)
{
    if (X == 0 || Y == 0)
        return 0;
    else if ((n_x == 1 && n_y == 1) || n_x == 1 || n_y == 1)
        return X * Y;
    else
    {
        int n_x0 = n_x / 2;
        int n_x1 = n_x - n_x0;

        int n_y0 = n_y / 2;
        int n_y1 = n_y - n_y0;

        long a = (long)(X / pow(10, n_x0));
        long b = (long)(X % (long)pow(10, n_x0));
        long c = (long)(Y / pow(10, n_y0));
        long d = (long)(Y % (long)pow(10, n_y0));

        long E = bigIntMultiply_Nonideal(a, c, n_x1, n_y1);
        long F = bigIntMultiply_Nonideal(b, d, n_x0, n_y0);
        long G = bigIntMultiply_Nonideal((long)(a * pow(10, n_x0) - b), (long)(d - c * pow(10, n_y0)), n_x1, n_y1);

        return (long)(E * pow(10, (n_x0 + n_y0)) + (G + E * pow(10, (n_x0 + n_y0)) + F) + F);
    }
}

3. 运行结果展示

  1. 理想状态下;
    运行截图
  2. 非理想状态下;
    运行截图

(注:运行计算的整数并不足够大,这里仅仅是举个栗子!)

三、友情链接~


最后,非常欢迎大家来讨论指正哦!

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值