c++大整数乘法

2021/5

 

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

以下复杂度分析有问题,在于 划分为 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,如下图:

则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;
}

```

 ```

// 三次乘法。由于还没有实现大整数减法(或支持负数的加法),暂时还是伪代码
#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

Before

 

这里不是必须用c++的话不推荐用c++大整数,py和java的支持要好得多。

大整数类  (非负)

#include <iostream>

#include <vector>

#include <string>

using namespace std;

struct BigInteger{

    static const int BASE=100000000;

    static const int WIDTH=8;

    vector<int> s;

 

    BigInteger(long long num=0){*this = 0}//构造函数

    BigInteger operator =(long long num){

s.clear();

do{

s.push_back(num%BASE);

num/=BASE;

}while(num>0);

return *this;

}

BigInteger operator = (const string& str){

s.clear();

        int x,len=(str.length()-1)/WIDTH+1;

        for(int i=0;i<len;i++){

            int end=s.length()-i*WIDTH;

            int start=max(0,end-WIDTH);

            sscanf(str.substr(start,end).c_str(),"%d",&x);

            s.push_back(x);

        }

 

        return *this;

    }

 

    BigInteger operator + (const BigInteger &b) const {

        BigInteger c;

        c.s.clear();

        int i,g;

        int x;

        for(i=0,g=0;;i++){

            if(g==0&&i>=s.size()&&i>=b.s.size()){//无进位,两个BigInteger实例均已遍历完成

                break;

            x=g;

            if(i<s.size())

                x+=s[i];

            if(i<b.s.size())

                x+=b.s[i];

            c.s.push_back(x%BASE);

            g=x/BASE;

        }

        return c;

    }

BigInteger operater+=(const BigInteger &b){

*this=*this+b;return *this;

}

    BigInteger operator - (const BigInteger& b) const

    {

        BigInteger c;

        c.s.clear();

        int MAX=std::max(s.size(),b.s.size());

        for(int i=0,g=0;;i++)

        {

            if(g==0&&i>=MAX)

                break;

            int x=g;

            if(i<s.size())

                x+=s[i];

            if(i<b.s.size())

                x-=b.s[i];

            if(i==MAX-1)

                c.s.push_back(x%BASE);

            else

                c.s.push_back(abs(x%BASE));

            g=x/BASE;

        }

        return c;

    }

    BigInteger operator -= (const BigInteger& b)

    {

        *this=*this-b;

        return *this;

    }

    BigInteger operator * (const BigInteger& b)

    {

        std::stringstream ss;

        for(int i=s.size()-1;i>=0;i--)

            ss<<s[i];

        std::string operand1=ss.str();

        ss.str("");

        for(int i=b.s.size()-1;i>=0;i--)

            ss<<b.s[i];

        std::string operand2=ss.str();

        std::vector<int> c,d,temp;

        for(int i=operand1.length()-1;i>=0;i--)

            c.push_back(operand1[i]-'0');

        for(int i=operand2.length()-1;i>=0;i--)

            d.push_back(operand2[i]-'0');

        int MAX=std::max(c.size(),d.size());

        for(int i=0;i<MAX*2+1;i++)

            temp.push_back(0);

        for(int i=0;i<c.size();i++)

            for(int j=0;j<d.size();j++)

                temp[i+j]+=c[i]*d[j];

        for(int i=0;i<2*MAX+1;i++)

            if(temp[i]>9)

            {

                temp[i+1]+=temp[i]/10;

                temp[i]%=10;

            }

        int m=2*MAX;

        while(temp[m]==0)

            m--;

        BigInteger another;

        another.s.clear();

        int len=(m-1)/WIDTH+1;

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

            another.s.push_back(0);

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

        {

            int x=1;

            int k=0;

            int end=std::min(m+1,(i+1)*WIDTH);

            int start=i*WIDTH;

            for(int j=start;j<end;j++)

            {

                k+=x*temp[j];

                x*=10;

            }

            another.s[i]=k;

        }

        return another;

    }

    BigInteger operator *= (const BigInteger& b)

    {

        *this=*this*b;

        return *this;

    }

    //自己写的除法,可以实现像int型一样的效果

    BigInteger operator / (const BigInteger& b)

    {

        std::string operand1,operand2,result;

        std::stringstream ss;

        for(int i=s.size()-1;i>=0;i--)

            ss<<s[i];

        operand1=ss.str();

        ss.str("");

        for(int i=b.s.size()-1;i>=0;i--)

            ss<<b.s[i];

        operand2=ss.str();

        int len1,len2;

        len1=operand1.length();

        len2=operand2.length();

        if(len1<len2)  //若操作数1小于操作数2,返回0

            return 0;

        if(*this==b)    //若两数相等,返回1,这里用到下面的“==”重载运算符

            return 1;

        std::vector<int> c,d;

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

        {

            c.push_back(operand1[i]-'0');

            if(i<len2)

                d.push_back(operand2[i]-'0');

            else

                d.push_back(0);

        }

        int time=len1-len2;

        int len=len1;

        int k,l=0;

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

        {

            int ok=1;

            k=0;

            do{

                if(c[l]==0)

                {

                    l++;

                    ok=0;

                    len1--;

                }

                if(len==len1)

                {

                    int j=0;

                    while(j<len2)

                    {

                        if(c[i+j]>d[j])    //第一次大就表示operand1 > operand2

                        {

                            ok=1;

                            break;

                        }

                        else if(c[i+j]<d[j])      //第一次小就表示operand1 < operand2

                        {

                            ok=0;

                            break;

                        }

                        j++;

                    }

                }

                if(ok)

                {

                    for(int j=0;j<len;j++)

                    {

                        c[j+i]-=d[j];

                        if(c[j+i]<0)

                        {

                            c[j+i-1]--;

                            c[j+i]+=10;

                        }

                    }

                    k++;

                }

            }while(ok);

            len--;

            result+=k+'0';

        }

        BigInteger temp;

        temp=result;

        return temp;

    }

    BigInteger operator /= (const BigInteger& b)

    {

        *this=*this/b;

        return *this;

    }

    //以下的重载方法全都在上面的四则运算上编写,不再介绍

    BigInteger operator % (const BigInteger& b)

    {

        BigInteger c;

        c=*this-(*this/b)*b;

        return c;

    }

    BigInteger operator %= (const BigInteger& b)

    {

        *this=*this%b;

        return *this;

    }

    bool operator < (const BigInteger& b) const

    {

        if(s.size()!=b.s.size())

            return s.size()<b.s.size();

        for(int i=s.size()-1;i>=0;i--)

            if(s[i]!=b.s[i])

                return  s[i]<b.s[i];

        return false;//相等

    }

    bool operator > (const BigInteger& b) const

    {

        return b<*this;

    }

    bool operator <= (const BigInteger& b) const

    {

        return !(b<*this);

    }

    bool operator >= (const BigInteger& b) const

    {

        return !(*this<b);

    }

    bool operator != (const BigInteger& b) const

    {

        return *this<b||*this>b;

    }

    bool operator == (const BigInteger& b) const

    {

        return !(*this<b)&&!(*this>b);

    }

    friend std::ostream& operator << (std::ostream& out,const BigInteger& x)

    {

        out<<x.s.back();

        for(int i=x.s.size()-2;i>=0;i--)

        {

            char buf[20];

            sprintf(buf,"%08d",x.s[i]);

            for(int j=0;j<strlen(buf);j++)

                out<<buf[j];

        }

        return out;

    }

    friend std::istream& operator >> (std::istream& in,BigInteger& x)

    {

        std::string s;

        if(!(in>>s))

            return in;

        x=s;

        return in;

    }

};

istream& operator >> (istream &in, BigInteger &x){

    string s;

    if(!(in>>x)) return in;

    x=s;

    return in;

}

ostream& operator << (ostream &out,const BigInteger &x){

out << x.s.back();//最高位不足8位的预防处理

    int i;

    for(i=x.s.size()-2;i>=0;i--){

char buf[20];

        sprintf(buf,"%08d",x.s[i]);//不足8位补0

for(int j=0;j<strlen(buf);j++)

        out<<buf[j];

    }

    return out;

}

说明:    static const int BASE=100000000;这个常数不属于 BigInteger类型的结构体变量,而属于 BigInteger这个类型,称为静态成员变量。在 BigInteger的成员函数内可以直接使用,但是在其他地方,用 BigInteger::BASE

posted @ 2019-07-01 23:44  Erio  阅读(1364)  评论(0编辑  收藏  举报