zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    清除System.Web.HttpRuntime.Cache缓存
    C# 自动添加文件头注释的方法
    MVC中为站点添加是否开启过滤器
    css 设置页面打印分页
    MVC core TempData Session has not been configured for this application or request.
    abp .net core hangfire JobStorage.Current property value has not been initialized
    数据库还原失败System.Data.SqlClient.SqlError: 无法执行 BACKUP LOG,因为当前没有数据库备份
    无法执行程序。所执行的命令为 "C:WindowsMicrosoft.NETFramework64v4.0.30319csc.exe" /noconfig /fullpaths @"C:WindowsMicrosoft.NETFramework64v4.0.30319Temporary ASP.NET Files oot411ea3248a9fbaun5r0xd.c
    ABP select2 在模态框中搜索框无法输入
    asp access 数据库连接失败(未指定的错误)
  • 原文地址:https://www.cnblogs.com/lqerio/p/11117608.html
Copyright © 2011-2022 走看看