【算法/C语言】大整数乘法(分治)

题目:

用分治算法编程实现两个n位十进制大整数的乘法运算。

思路:

参考大整数乘法的详解
伪码:
Function MulOfLargeInt(X,Y,n)**
输入:n位乘数X,Y,位数n
输出:XY的乘积
**1.if X = 0 or Y = 0 ; return 0
2.else if digit = 0 ; return XY
3.else
4.A ← X的前n/2位
5.B ← X的后n/2位
6.C ← Y的前n/2位
7.D ← Y的后n/2位
8.AC ← MulOfLargeInt(A,C,n/2)//A
C
9.BD ← MulOfLargeInt(B,D,n/2)//B*D
10.ABCD ← MulOfLargeInt((A-B),(D-C),n/2)+AC+BD
11.if n为奇数
12.XY ← AC * 10 ^ (n-1) + ((A-B)(D-C)+AC + BD) * 10 ^ n/2 + BD
13.else n为偶数
14.XY ← AC * 10 ^ n + ((A-B)(D-C) + AC + BD) * 10 ^ n/2 + BD

时间复杂度:O(n^log3)

实现:

#include<stdio.h>
#include<math.h>

long long divide_conquer(long long X, long long Y, int digit){
	
	long long A,B,C,D,AC,BD,ABCD;
	//printf("x=%lld\ty=%lld\t位数=%d\t\n",X,Y,digit);
	if(X == 0 || Y == 0){
		return 0; 
	}else if(digit == 1){
		return X*Y;
	}else{
		A = X/pow(10,digit / 2);	
		//printf("a=%lld\t",A);
			
		B = X % (int)pow(10,digit / 2);
		//printf("b=%lld\t",B);
		
		C = Y / pow(10,digit / 2);
		//printf("c=%lld\t",C);
		
		D = Y % (int)pow(10,digit / 2);
		//printf("d=%lld\t\n",D);
		
		AC = divide_conquer(A,C,digit / 2);
		//printf("ac=%lld\t",AC);
		

		BD = divide_conquer(B,D,digit / 2);
		//printf("bd=%lld\t\n",BD);
		
		//printf("A-B = %lld\t",A-B);
		//printf("D-C = %lld\n",D-C);
		ABCD = divide_conquer((A - B),(D - C),digit / 2) + AC + BD;
		
		//如果是位数是偶数,公式为:XY = AC*10的n次方 +((A-B)(D-C)+AC+BD)*10的n/2次方 + BD 
		//如果是位数是奇数,公式为:XY = AC*10的(n-1)次方 +((A-B)(D-C)+AC+BD)*10的n/2次方 + BD 
		if(digit%2 == 0){
			//printf("A=%lld\tB=%lld\tC=%lld\tD=%lld\tAC=%lld\tBD=%lld\tABCD=%lld\t\n",A,B,C,D,AC,BD,ABCD);
			//printf("t=%lld\n",(AC * pow(10,digit) + ABCD * pow(10,digit / 2) + BD));
			return AC *  pow(10,digit) + ABCD * pow(10,digit / 2) + BD;				
		}else{
			//printf("A=%lld\tB=%lld\tC=%lld\tD=%lld\tAC=%lld\tBD=%lld\tABCD=%lld\t\n",A,B,C,D,AC,BD,ABCD);
			//printf("t=%lld\n",(AC *  pow(10,digit-1) + ABCD *  pow(10,digit / 2) + BD));
			return AC *  pow(10,digit-1) + ABCD *  pow(10,digit / 2) + BD;		
		}	
	}
}

int main(){
	long long x,y,product;
	int digit;
	printf("请输入X:");
	scanf("%lld",&x);
	printf("请输入Y:");
	scanf("%lld",&y);
	int t = x;
	do{
		digit++;
		t = t / 10;
	}while(t != 0);
	printf("X=%lld\tY=%lld\tdigit=%d\t\n",x,y,digit);
	product = divide_conquer(x,y,digit);
	printf("X * Y = %lld",product);
}

遇到的问题:

1、如果只用int类型的话,6位数的乘法运算会出现负值。
2、如果是位数是偶数,公式为:XY = AC*10的n次方 +((A-B)(D-C)+AC+BD)10的n/2次方 + BD ;
如果是位数是奇数,公式为:XY = AC
10的(n-1)次方 +((A-B)(D-C)+AC+BD)*10的n/2次方 + BD 。

  • 7
    点赞
  • 52
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
以下是使用分治算法进行大整数乘法C语言代码: ```c #include<stdio.h> #include<string.h> #include<stdlib.h> #include<math.h> // 功能:高精度加法 // 输入:两个字符串,代表两个被加数 // 输出:返回一个新的字符串,代表两个被加数的和 char* add(char* a, char* b){ int len_a = strlen(a); int len_b = strlen(b); int len_c = (len_a > len_b) ? len_a + 1 : len_b + 1;// 结果字符串的长度,加一是因为可能进 char* c = (char*)malloc((len_c + 1) * sizeof(char)); int i, j, k, carry = 0; for(i = len_a - 1, j = len_b - 1, k = len_c - 1; k >= 0; i--, j--, k--){// 从低到高同时遍历两个字符串 int da = (i >= 0) ? a[i] - '0' : 0;// 若已经遍历完,则赋值为0 int db = (j >= 0) ? b[j] - '0' : 0; int dc = da + db + carry;// 计算当前的和 carry = dc / 10;// 计算下一的进 c[k] = dc % 10 + '0';// 将当前的和的个放入结果字符串中 } while(c[0] == '0') c++;// 去掉无用的前导0 char* ans = (char*)malloc((len_c - (c - c)) * sizeof(char)); strcpy(ans, c);// 将结果字符串的内容复制到新的字符串中 free(c);// 释放内存 return ans; } // 功能:高精度减法 // 输入:两个字符串,代表被减数和减数 // 输出:返回一个新的字符串,代表被减数减去减数的差 char* sub(char* a, char* b){ int len_a = strlen(a); int len_b = strlen(b); int len_c = (len_a > len_b) ? len_a : len_b;// 结果字符串的长度,不加一 char* c = (char*)malloc((len_c + 1) * sizeof(char)); int i, j, k, borrow = 0; for(i = len_a - 1, j = len_b - 1, k = len_c - 1; k >= 0; i--, j--, k--){// 从低到高同时遍历两个字符串 int da = (i >= 0) ? a[i] - '0' : 0;// 若已经遍历完,则赋值为0 int db = (j >= 0) ? b[j] - '0' : 0; int dc = da - db - borrow;// 计算当前的差 borrow = 0; while(dc < 0){// 如果当前为负数,则向高 borrow++;// 借次数加1 dc += 10;// 当前加上10 } c[k] = dc % 10 + '0';// 将当前的差的个放入结果字符串中 } while(c[0] == '0' && c[1] != '\0') c++;// 去掉无用的前导0 char* ans = (char*)malloc((len_c - (c - c)) * sizeof(char)); strcpy(ans, c);// 将结果字符串的内容复制到新的字符串中 free(c);// 释放内存 return ans; } // 功能:高精度乘法 // 输入:两个字符串,代表两个被乘数 // 输出:返回一个新的字符串,代表两个被乘数的积 char* mul(char* a, char* b){ int len_a = strlen(a); int len_b = strlen(b); if(len_a == 0 || len_b == 0) return "0";// 特殊情况处理 if(len_a == 1 && a[0] == '0') return "0";// 特殊情况处理 if(len_b == 1 && b[0] == '0') return "0";// 特殊情况处理 if(len_a == 1 && a[0] == '1') return b;// 特殊情况处理 if(len_b == 1 && b[0] == '1') return a;// 特殊情况处理 if(len_a < len_b){// 保证a的长度不小于b的长度 char* temp = a; a = b; b = temp; int temp_len = len_a; len_a = len_b; len_b = temp_len; } int i; char* a1 = (char*)malloc((len_a / 2 + 1) * sizeof(char)); for(i = 0; i < len_a / 2; i++) a1[i] = a[i];// 取a的前一半 a1[i] = '\0'; char* a2 = (char*)malloc((len_a - len_a / 2 + 1) * sizeof(char)); for(i = 0; i < len_a - len_a / 2; i++) a2[i] = a[i + len_a / 2];// 取a的后一半 a2[i] = '\0'; char* b1 = (char*)malloc((len_b / 2 + 1) * sizeof(char)); for(i = 0; i < len_b / 2; i++) b1[i] = b[i];// 取b的前一半 b1[i] = '\0'; char* b2 = (char*)malloc((len_b - len_b / 2 + 1) * sizeof(char)); for(i = 0; i < len_b - len_b / 2; i++) b2[i] = b[i + len_b / 2];// 取b的后一半 b2[i] = '\0'; char* p1 = mul(a1, b1);// 计算a1*b1 char* p2 = mul(a2, b2);// 计算a2*b2 char* p3 = mul(add(a1, a2), add(b1, b2));// 计算(a1+a2)*(b1+b2) char* p4 = sub(p3, add(p1, p2));// 计算(a1+a2)*(b1+b2)-a1*b1-a2*b2 char* mul_res = add(add(p1, p2), p4);// 将p1、p2和p4加起来就是最终结果 free(a1); free(a2); free(b1); free(b2); free(p1); free(p2); free(p3); free(p4); return mul_res; } int main(){ char a[10001] = "12345678901234567890"; char b[10001] = "98765432109876543210"; char* res = mul(a, b); printf("%s", res); return 0; } ```
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值