大整数乘法

通常印象中的乘法:

位数增加时,许多编程语言中,往往连long_int类型都无法存储一定程度上的大整数

根据乘法算式的思想,将大整数分块计算,每个子运算都是一位数乘一位数,通过数组的形式输出到屏幕,可以做到所谓的大整数乘法

#include <iostream>
#include <cstring>
using namespace std;

const int MAX_Length = 1000;

void long_multiplication(int* res, int* num1, int* num2);

void long_multiplication(int* res, int* num1, int* num2) {
	//num1[0]和num2[0]存储位数,这里res[0]取其加和,因为2位数乘2位数,最多4位数,99*99=9801
	res[0] = num1[0] + num2[0];
	//逐位相乘,想不明白搞个11*11,看一下121中的2是怎么来的
	for (int i = 1; i <= num1[0]; i++) {
		for (int j = 1; j <= num2[0]; j++) {
			res[i + j] += num1[i] * num2[j];
		}
	}
	//因为有res中有2位数,所以处理进位
	for (int x = 1; x <= res[0]; x++) {
		if (res[x] < 10) {
			//小于10没有事了,让它跳出当前循环,继续走判断下一个res
			continue;
		}
		else {
			//让它的前一位加进位
			res[x + 1] += res[x] / 10;
			//自身去模10
			res[x] = res[x] % 10;
			//循环次数一定要等于大整数结果的长度,res[0]还要自加
			x == res[0] && res[0]++;
		}
	}
}

int main(int argc, char** argv) {

	char str1[MAX_Length], str2[MAX_Length];
	int num1[MAX_Length], num2[MAX_Length], res[MAX_Length] = { 0 };  //注意res数组需要初始化,否则结果可能不正确

	cin >> str1;
	cout << "imput the 2" << endl;
	cin >> str2;
	//获取num1大数长度
	num1[0] = strlen(str1);
	//倒着写入num1,2的数组
	for (int i = 0; str1[i]; i++) {
		num1[num1[0] - i] = str1[i] - '0';
	}
	//获取num1大数长度
	num2[0] = strlen(str2);
	for (int i = 0; str2[i]; i++) {
		num2[num2[0] - i] = str2[i] - '0';
	}

	long_multiplication(res, num1, num2);

	for (int i = res[0]; i >=2; i--) { //第0位用来保存长度,第一位并没有使用
		std::cout << res[i];
	}
	cout << endl;
	return 0;

}

这种算法的时间复杂度是n^2量级的,有没有一种方法能在保证解决大整数乘法情况下,适当降低时间复杂度

根据分治法的思想,将一个大问题,转换为多个子问题,然后将比较容易操作的子问题得出结果,再次合并,得到原问题的结果

对于大整数乘法,我们同样采取这样的思想

当子问题中的算式分裂到个位数乘个位数,求和合并,这实际上与分块算式乘法很类似,实际上根据分治的思想,每次都是将大整数一分为二,每一部分乘属于它的数量级。

A*B = (A1+A2)*(B1+B2) = (A11+A12)*(A21+A22)*(B11+B12)*(B21+B22)=.........

根据该逻辑,推测时间复杂度为log2N的数量级

为了代码和思路的简洁性,采用递归程序

#include <cstdio>
#include <cmath>

/*递归思想
* 对X = 1234 和 Y = 5678来分析:

divideConquer(1234, 5678, 4)
————————————————————————
X=1234 | A=12 | B=34 | A-B=-22

Y=5678 | C=56 | D=78 | D-C=22

三次递归:
AC = divideConquer(12, 56, 2)
BD = divideConquer(34, 78, 2)
(A-B)(D-C) = divideConquer(-22, 22, 2)

AC递归
————————————————————————

X=12 | A1=1 | B1=2 | A1-B1=-1

Y=56 | C1=5 | D1=6 | D1-C1=1

A1*C1 = divideConquer(1, 5, 1) = 5
B1*D1 = divideConquer(2, 6, 1) = 12
(A1-B1) * (D1-C1) = divideConquer(-1, 1, 1) = -1;

所以AC递归求得的值为:5 * 10 ^ 2 + (-1 + 5 + 12)* 10 + 12 = 672

同理可得 BD = 2652 和 (A-B)(D-C) = -484

最终可得 X * Y = 7006652
*/

using namespace std;

int long_multiplication(int* x, int* y, int len) {
	if (*x == 0 || *y == 0) {
		return 0;
	}
	else if(len == 1){
		return(*x) * (*y);
	}
	else {
		int A_F = (int)*x / pow(10, (int)len / 2);//A大整数的第一部分

		int A_S = *x - A_F * pow(10,(int)len /2);//A大整数的第二部分(分界点n/2)

		int B_F = (int)*y / pow(10, (int)len / 2);//B大整数的第一部分

		int B_S = *y - B_F * pow(10, (int)len / 2);//B大整数的第二部分

		int A_FmulB_F = long_multiplication(&A_F, &B_F, len / 2);//第一部分与第一部分相乘

		int A_SmulB_S = long_multiplication(&A_S, &B_S, len / 2);//第二部分与第二部分相乘
		//A1-B1
		int temp1 = A_F - A_S;
		//B2-B1
		int temp2 = B_S - B_F;

		int ALL_AB = long_multiplication(&temp1, &temp2, len / 2) + A_FmulB_F + A_SmulB_S;
		//AC * pow(10 , n) + ABDC * pow(10, (int)(n / 2)) + BD
		return A_FmulB_F * pow(10, len) + ALL_AB * pow(10, (int)(len / 2)) + A_SmulB_S;
	}
}
int main(int argc, char** argv[]) {
	int A;
	int B;
	A = 1234;
	B = 5678;
	printf("%d", long_multiplication(&A, &B, 4));
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值