用分治法实现大整数乘法java_分治法实现大整数乘法【C++语言】

本文介绍了如何使用分治法来实现大整数的乘法运算,详细阐述了算法思路,并提供了C++代码实现。通过将大整数拆分为两部分,再进行递归计算,减少了乘法操作的次数。代码包括了对整数范围内的乘法以及大整数字符串形式的乘法处理。
摘要由CSDN通过智能技术生成

若是实现传统算法中两个n位整数相乘,第一个整数中的n个数字都要分别乘以第二个整数的n个数字,这样就一共要作n*n次乘法。看上去设计一个乘法次数少于n*n的算法是不可能的,但事实证实并不是如此,能够使用分治的思想计算两个大整数的相乘。c++

首先从仅有两位数字的两个数12和34考虑,12 = 1 * 10 + 2,34 = 3 * 10 + 4算法

把它们相乘:408 = 12 * 34 = (1 * 3) * 100 + (1 * 4 + 2 * 3) * 10 + 2 * 4spa

上式虽然产生了正确的结果,可是也使用了4次乘法。可是中间项的计算结果能够使用已经计算过的1 * 3和2 * 4来简化依次乘法设计

1 * 4 + 2 * 3 = (1 + 4) * ( 2 + 3) - 1 * 3 - 2 * 4code

用更通常的字母代替上面的过程,能够获得以下的公式:递归

c = a * b = c2*100 + c1*10 + c0,其中c2 = a1 * b1, c0 = a0 * b0, c1 = a1 * b0 + a0 * b1 = (a1 + a0) * (b1 + b0)  - (c2 +c0)ci

a的前半部分记做a1, 后半部分记做a0,b的前半部分记做b1, 后半部分记做b0rem

对于位数更高的n来讲字符串

c = a * b string

= (a1 * 10 ^ n/2 + a0) * (b1 * 10 ^ n/2 + b0)

= (a1*b1)*10^n + (a1 * b0 + a0 * b1) * 10 ^ n/2 + (a0 * b0)

= c2 * 10 ^ n + c1 * 10 ^ n/2 + c0

若是不考虑大整数的要求,仅考虑int范围内的整数相乘,则代码实现以下

#include

using namespace std;

int qpow(int n, int a = 10) {

int ret = 1;

while (n) {

if (n & 1) ret = ret * a;

a = a * a;

n >>= 1;

}

return ret;

}

int len(int n) {

int a = 0;

while (n) {

n /= 10;

++a;

}

return a;

}

int bigmul(int a, int b, int n) {

if (n <= 2)

return a * b;

int a1 = a / qpow(n / 2);

int a0 = a % qpow(n / 2);

int b1 = b / qpow(n / 2);

int b0 = b % qpow(n / 2);

int c2 = bigmul(a1, b1, n / 2);

int c0 = bigmul(a0, b0, n / 2);

int c1 = bigmul(a1 + a0, b1 + b0, n / 2) - (c2 + c0);

return c2 * qpow(n) + c1 * qpow(n / 2) + c0;

}

int main() {

int a, b, n;

while (cin >> a >> b) {

n = qpow(ceil(log2(max(len(a), len(b)))), 2);

cout << bigmul(a, b, n) << endl;

}

}

若是进一步考虑大整数的要求,则能够经过字符串模拟操做实现,具体代码以下:

#include

using namespace std;

template

int toInt(T s)

{

// 将字符串或字符转化为数字

int res;

stringstream ss;

ss << s;

ss >> res;

return res;

}

string toStr(int n)

{

// 将数字转为字符串

string res;

stringstream ss;

ss << n;

ss >> res;

return res;

}

void addZero(string &s, int n, bool pre = true)

{

// 在字符串前或者字符串后添加0(默认为前)

string temp(n, '0');

s = pre ? temp + s : s + temp;

}

void removeZero(string &s)

{

// 去除前导零

int i = 0;

while (i < s.length() && s[i] == '0')

++i;

if (i < s.length())

s = s.substr(i);

else

s = "0";

}

string add(string a, string b)

{

// 大数加法(只考虑a+b非负)

string res;

removeZero(a);

removeZero(b);

reverse(a.begin(), a.end());

reverse(b.begin(), b.end());

int l = max((int)a.size(), (int)b.size());

for (int i = 0, j = 0; j || i < l; ++i)

{

int t = j;

if (i < a.size())

t += toInt(a[i]);

if (i < b.size())

t += toInt(b[i]);

int q = t % 10;

res = char(q + '0') + res;

j = t / 10;

}

return res;

}

string sub(string a, string b)

{

// 大数减法(只考虑a-b非负)

string res;

removeZero(a);

removeZero(b);

reverse(a.begin(), a.end());

reverse(b.begin(), b.end());

int lx = (int)a.size(), ly = (int)b.size(), j = 0;

//int* temp = new int[lx];

int *temp = (int *)calloc(lx, sizeof(int));

for (int i = 0; i < lx; ++i)

{

int ai = toInt(a[i]);

int bi = i < ly ? toInt(b[i]) : 0;

temp[j++] = ai - bi;

}

for (int i = 0; i < lx; ++i)

{

if (temp[i] < 0)

{

temp[i] += 10;

--temp[i + 1];

}

}

for (int i = lx - 1; i >= 0; --i)

{

res += toStr(temp[i]);

}

return res;

}

string mul(string a, string b)

{

// 大数乘法(只考虑a,b非负)

string res;

int n = 2;

if (a.size() > 2 || b.size() > 2)

{

n = 4;

while (n < a.size() || n < b.size())

n <<= 1;

addZero(a, n - (int)a.size());

addZero(b, n - (int)b.size());

}

if (a.size() == 1)

addZero(a, 1);

if (b.size() == 1)

addZero(b, 1);

if (n == 2)

{ // 递归终止

int temp = toInt(a) * toInt(b);

res = toStr(temp);

}

else

{

string a1, a0, b1, b0, c2, c1, c0;

a1 = a.substr(0, n / 2);

a0 = a.substr(n / 2);

b1 = b.substr(0, n / 2);

b0 = b.substr(n / 2);

c2 = mul(a1, b1);

c0 = mul(a0, b0);

c1 = sub(mul(add(a0, a1), add(b0, b1)), add(c2, c0));

addZero(c2, n, false);

addZero(c1, n / 2, false);

res = add(add(c2, c1), c0);

}

return res;

}

int main()

{

string a, b;

while (cin >> a >> b)

{

cout << mul(a, b) << endl;

}

}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值