大整数乘法c语言代码_[算法]大整数乘法

利用二分法和递归计算任意长度整数相乘

以下复杂度分析有问题,在于 划分为 A12(n2),这样才相当于移位;

程序中采用string直接+'0'的方式来*10

第一次的代码有漏洞,已更正

我们可以把规模n变成n/2和n/2(把以1位为单位规模为n的问题 变成 以n/2为单位的规模为2的问题),把规模m变成m/2和m/2(把以1位为单位规模为m的问题 变成 以m/2为单位的规模为2的问题),如此,原来的大整数相乘就变成了两个2位数相乘,只不过低位向高位的进制不再是10,而是和。更一般地,我们把整数A由规模n分为n1和n2,把整数B由规模m分为m1和m2,如下图:

651864cf16eff5ad7eb0baf08998c280.png

b994ed02bb9509943b87f50992bbbd0b.png

则A分为n1位的A1和n2位,B分为m1位的B1和m2位的B2,如下式所示:

以此类推,我们可以把A1、A2、B1、B2继续划分,直至最小单位。(这里在编程时需要用递归实现)

于是

注意用2^n做乘法相当于移位运算,需要O(n)时间。此公式中有4次乘法运算,3次加法运算,则

故T(n)=O(n^2)

A1B1 A2B2已经计算过,故乘法运算次数减少为3次

产生递推式

// 四次乘法,3次加法
#include <iostream>
#include <string>
#include <sstream>

using namespace std;

string multi(string A, string B); //计算大整数相乘
string Plus(string q, string w, string e, string r); //计算大整数相加
stringstream ss;

int main() {
      string A, B;
      while (cin >> A >> B) {
      cout << multi(A, B) << endl;
      }
      return 0;
}

string multi(string A, string B) {
      int len_A = A.length();
      int len_B = B.length();
      if (len_A == 1) {
      if (len_B == 1) { //最基本的情况:A和B都是一位数,把A、B从string转为int(我这里用的stringstream),然后相乘后转回为string型return回去。
      ss << A;
      int a;
      ss >> a;
      ss.clear();
      ss << B;
      int b;
      ss >> b;
      ss.clear();
      ss << b*a;
      string str_out;
      ss >> str_out;
      ss.clear();
      return str_out;
      }
      else {//A是个位数,B不是的情况下,按照分治的思想把B分开分别与A相乘。
      string B1, B2;
      B1 = B.substr(0, len_B / 2);
      B2 = B.substr(len_B / 2);
      string AB1 = multi(A, B1);
      string AB2 = multi(A, B2);
      cout<<AB1<<endl<<AB2<<endl;
      if (AB2.length() > B2.length()) {   //此时AB2最多比B2多出一位
      string str = AB2.substr(0, 1);
        /*ss << AB1;     漏洞,此时AB1可能已经超出int范围了
        int ab1;
        ss >> ab1;*/
        string tp0(AB1.length()-1,'0');
        str=tp0+str;
        string u0(AB1.length(),'0');
        AB1=Plus(AB1,str,u0,u0);
        return AB1 + AB2.substr(1);
      }
      else
        return AB1 + AB2;
        }
    }
      else {
      if (len_B == 1) {//B是个位数,A不是的情况与上述A是个位数B不是的情况相同。
      string A1, A2;
      A1 = A.substr(0, len_A / 2);
      A2 = A.substr(len_A / 2);
      string A1B = multi(A1, B);
      string A2B = multi(A2, B);
      if (A2B.length() > A2.length()) {
        string str = A2B.substr(0, 1);
        string tp0(A1B.length()-1,'0');
        str=tp0+str;
        string u0(A1B.length(),'0');
        A1B=Plus(A1B,str,u0,u0);
        return A1B + A2B.substr(1);
        }
      else {
        return A1B + A2B;
        }
        }
      else {//A和B都不是个位数,就按照上述方法分治就可以了,只是为了最后相加的时候方便,把返回的四个部分都用0凑成了位数相同的。
      string A1, A2, B1, B2;
      A1 = A.substr(0, len_A / 2);
      A2 = A.substr(len_A / 2);
      B1 = B.substr(0, len_B / 2);
      B2 = B.substr(len_B / 2);
      string part1_ = multi(A1, B1);
      string part1_0(A2.length()+B2.length(), '0');   //长度为A2.length()+B2.length()的0串
      part1_ = part1_ + part1_0;                      //A1B1*10(n2,m2)
      string part2_ = multi(A2, B2);
      string part2_00(part1_.length() - part2_.length(), '0');
      part2_ = part2_00 + part2_;                     //A2B2,高位补0
      string part3_ = multi(A1, B2);
      string part3_0(A2.length(), '0');
      part3_ = part3_ + part3_0;                    //A1B2*10(n2)
      string part3_00(part1_.length() - part3_.length(), '0');
      part3_ = part3_00 + part3_;
      string part4_ = multi(A2, B1);
      string part4_0(B2.length(), '0');
      part4_ = part4_ + part4_0;
      string part4_00(part1_.length() - part4_.length(), '0');
      part4_ = part4_00 + part4_;
      return Plus(part1_, part2_, part3_, part4_);   //未改进的第一种算法
    }
    }
}

string Plus(string q, string w, string e, string r) { //大整数相加,qwer位数相同
      int len_q = q.length();
      string y, out;
      int a, b, c, d;
      for (int i = 1; i <= len_q; i++) {  //逐位相加
    ss << q.substr(len_q - i, 1);
    ss >> a;
    ss.clear();
    ss << w.substr(len_q - i, 1);
    ss >> b;
    ss.clear();
    ss << e.substr(len_q - i, 1);
    ss >> c;
    ss.clear();
    ss << r.substr(len_q - i, 1);
    ss >> d;
    ss.clear();
    ss << a + b + c + d;
    ss >> y;
    ss.clear();
      if (i == 1)
      out = y;
      else if (out.length() > i - 1) {  //进一位
      ss << out.substr(0, 1);
      ss >> a;
      ss.clear();
      ss << y;
      ss >> b;
      ss.clear();
      ss << a + b;
      ss >> y;
      ss.clear();
      out = y + out.substr(1);
    }
      else {
      out = y + out;
    }
    }
	return out;
}

3858520f672963cd365a574a8f8458a8.png
// 三次乘法。由于还没有实现大整数减法(或支持负数的加法),暂时还是伪代码
#include <iostream>
#include <string>
#include <sstream>

using namespace std;

string multi(string A, string B); //计算大整数相乘
string Plus(string q, string w, string e, string r); //计算大整数相加
stringstream ss;

int main() {
      string A, B;
      while (cin >> A >> B) {
      cout << multi(A, B) << endl;
      }
      return 0;
}

string multi(string A, string B) {
      int len_A = A.length();
      int len_B = B.length();
      if (len_A == 1) {
      if (len_B == 1) { //最基本的情况:A和B都是一位数,把A、B从string转为int(我这里用的stringstream),然后相乘后转回为string型return回去。
      ss << A;
      int a;
      ss >> a;
      ss.clear();
      ss << B;
      int b;
      ss >> b;
      ss.clear();
      ss << b*a;
      string str_out;
      ss >> str_out;
      ss.clear();
      return str_out;
      }
      else {//A是个位数,B不是的情况下,按照分治的思想把B分开分别与A相乘。
      string B1, B2;
      B1 = B.substr(0, len_B / 2);
      B2 = B.substr(len_B / 2);
      string AB1 = multi(A, B1);
      string AB2 = multi(A, B2);
      cout<<AB1<<endl<<AB2<<endl;
      if (AB2.length() > B2.length()) {   //此时AB2最多比B2多出一位
      string str = AB2.substr(0, 1);
        /*ss << AB1;     漏洞,此时AB1可能已经超出int范围了
        int ab1;
        ss >> ab1;*/
        string tp0(AB1.length()-1,'0');
        str=tp0+str;
        string u0(AB1.length(),'0');
        AB1=Plus(AB1,str,u0,u0);
        return AB1 + AB2.substr(1);
      }
      else
        return AB1 + AB2;
        }
    }
      else {
      if (len_B == 1) {//B是个位数,A不是的情况与上述A是个位数B不是的情况相同。
      string A1, A2;
      A1 = A.substr(0, len_A / 2);
      A2 = A.substr(len_A / 2);
      string A1B = multi(A1, B);
      string A2B = multi(A2, B);
      if (A2B.length() > A2.length()) {
        string str = A2B.substr(0, 1);
        string tp0(A1B.length()-1,'0');
        str=tp0+str;
        string u0(A1B.length(),'0');
        A1B=Plus(A1B,str,u0,u0);
        return A1B + A2B.substr(1);
        }
      else {
        return A1B + A2B;
        }
        }
      else {//A和B都不是个位数,就按照上述方法分治就可以了,只是为了最后相加的时候方便,把返回的四个部分都用0凑成了位数相同的。
      string A1, A2, B1, B2;
      A1 = A.substr(0, len_A / 2);
      A2 = A.substr(len_A / 2);
      B1 = B.substr(0, len_B / 2);
      B2 = B.substr(len_B / 2);
      string part1_ = multi(A1, B1);
	  part1_ = multi(2, part1_);
      string part1_0(A2.length()+B2.length(), '0');   //长度为A2.length()+B2.length()的0串
      part1_ = part1_ + part1_0;                      //2*A1B1*10(n2,m2)
      string part2_ = multi(A2, B2);
	  part2_ =multi(2,part2_);
      string part2_00(part1_.length() - part2_.length(), '0');
      part2_ = part2_00 + part2_;                     //2*A2B2,高位补0
	  
	  
      string part3_ = A1;
      string part3_0(A2.length(), '0');             //(A1*10(n2)-A2)
      part3_ = part3_ + part3_0;                    //A1*10(n2)  伪代码
	  part3_= part_3-A2                             //大整数减法(或支持负数的大整数加法),未实现
      
	  
	  
      string part4_ = B1;                           //(B2-B1*10(m2))
      string part4_0=(B2.length(), '0');
      part4_ = part4_ + part4_0;
	  part4_= B2-part4_;                        
	  
	  part5_= multi(part4_,part3_)
	  
      string part5_00(part1_.length() - part5_.length(), '0');
      part5_ = part5_00 + part5_;
	  string u0(part1_.length(), '0');
      return Plus(part1_, part2_, part5_, u0);   
    }
    }
}

string Plus(string q, string w, string e, string r) { //大整数相加,qwer位数相同
      int len_q = q.length();
      string y, out;
      int a, b, c, d;
      for (int i = 1; i <= len_q; i++) {  //逐位相加
    ss << q.substr(len_q - i, 1);
    ss >> a;
    ss.clear();
    ss << w.substr(len_q - i, 1);
    ss >> b;
    ss.clear();
    ss << e.substr(len_q - i, 1);
    ss >> c;
    ss.clear();
    ss << r.substr(len_q - i, 1);
    ss >> d;
    ss.clear();
    ss << a + b + c + d;
    ss >> y;
    ss.clear();
      if (i == 1)
      out = y;
      else if (out.length() > i - 1) {  //进一位
      ss << out.substr(0, 1);
      ss >> a;
      ss.clear();
      ss << y;
      ss >> b;
      ss.clear();
      ss << a + b;
      ss >> y;
      ss.clear();
      out = y + out.substr(1);
    }
      else {
      out = y + out;
    }
    }
	return out;
}

参考

https://blog.csdn.net/qq_36165148/article/details/81132525​blog.csdn.net
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
分治法是一种算法设计策略,通过将问题分解成更小的子问题,再通过将解合并起来来解决原始问题。在大整数乘法问题中,可以使用分治法来提高算法效率。 下面是一个使用C语言编写的分治法大整数乘法代码示例: #include <stdio.h> #include <math.h> long long int power(int a, int b) { if (b == 0) { return 1; } else { return a * power(a, b - 1); } } long long int multiply(long long int x, long long int y) { int n; if (x < 10 || y < 10) { return x * y; } n = fmax(log10(x) + 1, log10(y) + 1); int m = ceil(n / 2.0); long long int a = x / power(10, m); long long int b = x % power(10, m); long long int c = y / power(10, m); long long int d = y % power(10, m); long long int ac = multiply(a, c); long long int bd = multiply(b, d); long long int ad_bc = multiply(a + b, c + d) - ac - bd; return ac * power(10, 2 * m) + ad_bc * power(10, m) + bd; } int main() { long long int x, y; printf("请输入两个整数:"); scanf("%lld %lld", &x, &y); long long int result = multiply(x, y); printf("两数乘积为:%lld\n", result); return 0; } 在这个代码示例中,使用了递归来实现分治法的思想。首先判断输入的两个数是否小于10,如果是,则直接返回乘积。如果不是,则计算出这两个数的位数n,然后取n的一半向上取整得到m。分别将两个数的高位和低位等分为a、b、c、d四部分。 接着,使用递归调用multiply函数来计算ac、bd和ad_bc三个结果,最后将这三个结果按照指定的规则相加得到最终的乘积。 通过使用分治法,可以显著提高大整数乘法的效率。因为将问题分解成更小的子问题,每个子问题处理的数据规模更小,计算量相对减少,从而提高了算法的效率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值