1. 程式人生 > 其它 >和整數相乘_[演算法]大整數乘法

和整數相乘_[演算法]大整數乘法

技術標籤:和整數相乘

利用二分法和遞迴計算任意長度整數相乘

以下複雜度分析有問題,在於 劃分為 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,如下圖:

7ad0a1ef681895c0d9fbb615326d8b94.png

02b1ec69b78d77327abcaac76915e9bc.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;
}

64e2ac3bc379750cfcb36924cffb34fe.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