【暖*墟】关于{ 高精度 }的专题 C++高精度运算模板

ACM-高精度模板(综合篇)

能用int表示的数据视为单精度,否则为高精度。所有函数的设计均采用带返回值的形式。

本文包含:1.高精度加法;2.高精度减法

3.高精度乘法  1)高乘高朴素算法  2)高乘高FFT优化算法  3)高精度乘单精度

4.高精度除法  1)高精度除高精度  2)高精度除单精度

5.高精度取模  1)高精度对高精度取模  2)高精度对单精度取模

6.高精度阶乘;7.高精度;8.高精度GCD;9.高精度进制转换;10.高精度求平方根


1.高精度加法

传入参数约定:传入参数均为string类型,返回值为string类型

算法思想:倒置相加再还原。

算法复杂度:o(n)

    #include<iostream>  
    #include<cstring>  
    #include<algorithm>  
    using namespace std;  
    const int L=110;  
    string add(string a,string b)//只限两个非负整数相加  
    {  
        string ans;  
        int na[L]={0},nb[L]={0};  
        int la=a.size(),lb=b.size();  
        for(int i=0;i<la;i++) na[la-1-i]=a[i]-'0';  
        for(int i=0;i<lb;i++) nb[lb-1-i]=b[i]-'0';  
        int lmax=la>lb?la:lb;  
        for(int i=0;i<lmax;i++) na[i]+=nb[i],na[i+1]+=na[i]/10,na[i]%=10;  
        if(na[lmax]) lmax++;  
        for(int i=lmax-1;i>=0;i--) ans+=na[i]+'0';  
        return ans;  
    }  
    int main()  
    {  
        string a,b;  
        while(cin>>a>>b) cout<<add(a,b)<<endl;  
        return 0;  
    }  


2.高精度减法

传入参数约定:传入参数均为string类型,返回值为string类型

算法思想:倒置相减再还原。

算法复杂度:o(n)

    #include<iostream>  
    #include<cstring>  
    #include<algorithm>  
    using namespace std;  
    const int L=110;  
    string sub(string a,string b)//只限大的非负整数减小的非负整数  
    {  
        string ans;  
        int na[L]={0},nb[L]={0};  
        int la=a.size(),lb=b.size();  
        for(int i=0;i<la;i++) na[la-1-i]=a[i]-'0';  
        for(int i=0;i<lb;i++) nb[lb-1-i]=b[i]-'0';  
        int lmax=la>lb?la:lb;  
        for(int i=0;i<lmax;i++)  
        {  
            na[i]-=nb[i];  
            if(na[i]<0) na[i]+=10,na[i+1]--;  
        }  
        while(!na[--lmax]&&lmax>0)  ;lmax++;  
        for(int i=lmax-1;i>=0;i--) ans+=na[i]+'0';  
        return ans;  
    }  
    int main()  
    {  
        string a,b;  
        while(cin>>a>>b) cout<<sub(a,b)<<endl;  
        return 0;  
    }  

3.高精度乘法
1)高精度乘高精度的朴素算法

传入参数约定:传入参数均为string类型,返回值为string类型

算法思想:倒置相乘,然后统一处理进位,再还原。

算法复杂度:o(n^2)

    #include<iostream>  
    #include<cstring>  
    #include<algorithm>  
    using namespace std;  
    const int L=110;  
    string mul(string a,string b)//高精度乘法a,b,均为非负整数  
    {  
        string s;  
        int na[L],nb[L],nc[L],La=a.size(),Lb=b.size();//na存储被乘数,nb存储乘数,nc存储积  
        fill(na,na+L,0);fill(nb,nb+L,0);fill(nc,nc+L,0);//将na,nb,nc都置为0  
        for(int i=La-1;i>=0;i--) na[La-i]=a[i]-'0';//将字符串表示的大整形数转成i整形数组表示的大整形数  
        for(int i=Lb-1;i>=0;i--) nb[Lb-i]=b[i]-'0';  
        for(int i=1;i<=La;i++)  
            for(int j=1;j<=Lb;j++)  
            nc[i+j-1]+=na[i]*nb[j];//a的第i位乘以b的第j位为积的第i+j-1位(先不考虑进位)  
        for(int i=1;i<=La+Lb;i++)  
            nc[i+1]+=nc[i]/10,nc[i]%=10;//统一处理进位  
        if(nc[La+Lb]) s+=nc[La+Lb]+'0';//判断第i+j位上的数字是不是0  
        for(int i=La+Lb-1;i>=1;i--)  
            s+=nc[i]+'0';//将整形数组转成字符串  
        return s;  
    }  
    int main()  
    {  
        string a,b;  
        while(cin>>a>>b) cout<<mul(a,b)<<endl;  
        return 0;  
    }  


2)高精度乘高精度FFT优化算法

传入参数约定:传入参数均为string类型,返回值为string类型

算法思想:将两个高精度乘数每个数位上的数视为多项式对应的系数,用o(n*log(n))的复杂度转成点值形式,再利用o(n)的复杂度相乘,最后对点值进行差值,用o(n*log(n))的复杂度还原成多项式的形式,即原来的形式。

算法复杂度:o(n*log(n))

    #include <iostream>  
    #include <cstdio>  
    #include <algorithm>  
    #include <cstring>  
    #include <cmath>  
    #include <map>  
    #include <queue>  
    #include <set>  
    #include <vector>  
    using namespace std;  
    #define L(x) (1 << (x))  
    const double PI = acos(-1.0);  
    const int Maxn = 133015;  
    double ax[Maxn], ay[Maxn], bx[Maxn], by[Maxn];  
    char sa[Maxn/2],sb[Maxn/2];  
    int sum[Maxn];  
    int x1[Maxn],x2[Maxn];  
    int revv(int x, int bits)  
    {  
        int ret = 0;  
        for (int i = 0; i < bits; i++)  
        {  
            ret <<= 1;  
            ret |= x & 1;  
            x >>= 1;  
        }  
        return ret;  
    }  
    void fft(double * a, double * b, int n, bool rev)  
    {  
        int bits = 0;  
        while (1 << bits < n) ++bits;  
        for (int i = 0; i < n; i++)  
        {  
            int j = revv(i, bits);  
            if (i < j)  
                swap(a[i], a[j]), swap(b[i], b[j]);  
        }  
        for (int len = 2; len <= n; len <<= 1)  
        {  
            int half = len >> 1;  
            double wmx = cos(2 * PI / len), wmy = sin(2 * PI / len);  
            if (rev) wmy = -wmy;  
            for (int i = 0; i < n; i += len)  
            {  
                double wx = 1, wy = 0;  
                for (int j = 0; j < half; j++)  
                {  
                    double cx = a[i + j], cy = b[i + j];  
                    double dx = a[i + j + half], dy = b[i + j + half];  
                    double ex = dx * wx - dy * wy, ey = dx * wy + dy * wx;  
                    a[i + j] = cx + ex, b[i + j] = cy + ey;  
                    a[i + j + half] = cx - ex, b[i + j + half] = cy - ey;  
                    double wnx = wx * wmx - wy * wmy, wny = wx * wmy + wy * wmx;  
                    wx = wnx, wy = wny;  
                }  
            }  
        }  
        if (rev)  
        {  
            for (int i = 0; i < n; i++)  
                a[i] /= n, b[i] /= n;  
        }  
    }  
    int solve(int a[],int na,int b[],int nb,int ans[])  
    {  
        int len = max(na, nb), ln;  
        for(ln=0; L(ln)<len; ++ln);  
        len=L(++ln);  
        for (int i = 0; i < len ; ++i)  
        {  
            if (i >= na) ax[i] = 0, ay[i] =0;  
            else ax[i] = a[i], ay[i] = 0;  
        }  
        fft(ax, ay, len, 0);  
        for (int i = 0; i < len; ++i)  
        {  
            if (i >= nb) bx[i] = 0, by[i] = 0;  
            else bx[i] = b[i], by[i] = 0;  
        }  
        fft(bx, by, len, 0);  
        for (int i = 0; i < len; ++i)  
        {  
            double cx = ax[i] * bx[i] - ay[i] * by[i];  
            double cy = ax[i] * by[i] + ay[i] * bx[i];  
            ax[i] = cx, ay[i] = cy;  
        }  
        fft(ax, ay, len, 1);  
        for (int i = 0; i < len; ++i)  
            ans[i] = (int)(ax[i] + 0.5);  
        return len;  
    }  
    string mul(string sa,string sb)  
    {  
        int l1,l2,l;  
        int i;  
        string ans;  
        memset(sum, 0, sizeof(sum));  
        l1 = sa.size();  
        l2 = sb.size();  
        for(i = 0; i < l1; i++)  
            x1[i] = sa[l1 - i - 1]-'0';  
        for(i = 0; i < l2; i++)  
            x2[i] = sb[l2-i-1]-'0';  
        l = solve(x1, l1, x2, l2, sum);  
        for(i = 0; i<l || sum[i] >= 10; i++) // 进位  
        {  
            sum[i + 1] += sum[i] / 10;  
            sum[i] %= 10;  
        }  
        l = i;  
        while(sum[l] <= 0 && l>0)    l--; // 检索最高位  
        for(i = l; i >= 0; i--)    ans+=sum[i] + '0'; // 倒序输出  
        return ans;  
    }  
    int main()  
    {  
        cin.sync_with_stdio(false);  
        string a,b;  
        while(cin>>a>>b) cout<<mul(a,b)<<endl;  
        return 0;  
    }  

3)高精度乘单精度

传入参数约定:传入第一个参数为string类型,,第二个参数为int型,返回值为string类型

算法思想:倒置相乘,然后统一处理进位,再还原。

算法复杂度:o(n)

#include<iostream>  
#include<cstring>  
#include<algorithm>  
using namespace std;  
const int L=100005;  
int na[L];  
string mul(string a,int b)//高精度a乘单精度b  
{  
    string ans;  
    int La=a.size();  
    fill(na,na+L,0);  
    for(int i=La-1;i>=0;i--) na[La-i-1]=a[i]-'0';  
    int w=0;  
    for(int i=0;i<La;i++) na[i]=na[i]*b+w,w=na[i]/10,na[i]=na[i]%10;  
    while(w) na[La++]=w%10,w/=10;  
    La--;  
    while(La>=0) ans+=na[La--]+'0';  
    return ans;  
}  
int main()  
{  
    string a;  
    int b;  
    while(cin>>a>>b) cout<<mul(a,b)<<endl;  
    return 0;  
}  








C++高精度运算模板

(来自https://blog.csdn.net/code4101/article/details/23020525 膜拜dalao qwq)

  另一种版本的高精度类   功能:正整数的加、减、乘、除、取余、大小关系运算。

#include <cassert>   // assert  
#include <cstdio>    // printf,sprintf  
#include <cstring>   // strlen  
#include <iostream>  // cin,cout  
#include <string>    // string类  
#include <vector>    // vector类  
#include <algorithm> // max
using namespace std;  
      
const int maxn = 1000;  
struct BigInteger {  

    typedef unsigned long long LL;    
    static const int BASE = 100000000;  
    static const int WIDTH = 8;  
    vector<int> s;  
      
    BigInteger& clean(){while(!s.back()&&s.size()>1)s.pop_back(); return *this;}  
    BigInteger(LL num = 0) {*this = num;}  
    BigInteger(string s) {*this = s;}  
    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 = str.length() - i*WIDTH;  
            int start = max(0, end - WIDTH);  
            sscanf(str.substr(start,end-start).c_str(), "%d", &x);  
            s.push_back(x);  
        }  
        return (*this).clean();  
    }  
      
    BigInteger operator + (const BigInteger& b) const {  
        BigInteger c; c.s.clear();  
        for (int i = 0, g = 0; ; i++) {  
            if (g == 0 && i >= s.size() && i >= b.s.size()) break;  
            int 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 operator - (const BigInteger& b) const {  
        assert(b <= *this); // 减数不能大于被减数  
        BigInteger c; c.s.clear();  
        for (int i = 0, g = 0; ; i++) {  
            if (g == 0 && i >= s.size() && i >= b.s.size()) break;  
            int x = s[i] + g;  
            if (i < b.s.size()) x -= b.s[i];  
            if (x < 0) {g = -1; x += BASE;} else g = 0;  
            c.s.push_back(x);  
        }  
        return c.clean();  
    }  
    
    BigInteger operator * (const BigInteger& b) const {  
        int i, j; LL g;  
        vector<LL> v(s.size()+b.s.size(), 0);  
        BigInteger c; c.s.clear();  
        for(i=0;i<s.size();i++) for(j=0;j<b.s.size();j++) v[i+j]+=LL(s[i])*b.s[j];  
        for (i = 0, g = 0; ; i++) {  
            if (g ==0 && i >= v.size()) break;  
            LL x = v[i] + g;  
            c.s.push_back(x % BASE);  
            g = x / BASE;  
        }  
        return c.clean();  
    }  
    
    BigInteger operator / (const BigInteger& b) const {  
        assert(b > 0);  // 除数必须大于0  
        BigInteger c = *this;       // 商:主要是让c.s和(*this).s的vector一样大  
        BigInteger m;               // 余数:初始化为0  
        for (int i = s.size()-1; i >= 0; i--) {  
            m = m*BASE + s[i];  
            c.s[i] = bsearch(b, m);  
            m -= b*c.s[i];  
        }  
        return c.clean();  
    }  
    
    BigInteger operator % (const BigInteger& b) const { //方法与除法相同  
        BigInteger c = *this;  
        BigInteger m;  
        for (int i = s.size()-1; i >= 0; i--) {  
            m = m*BASE + s[i];  
            c.s[i] = bsearch(b, m);  
            m -= b*c.s[i];  
        }  
        return m;  
    }  
    
    // 二分法找出满足bx<=m的最大的x  
    int bsearch(const BigInteger& b, const BigInteger& m) const{  
        int L = 0, R = BASE-1, x;  
        while (1) {  
            x = (L+R)>>1;  
            if (b*x<=m) {if (b*(x+1)>m) return x; else L = x;}  
            else R = x;  
        }  
    }  
        
    BigInteger& operator += (const BigInteger& b) {*this = *this + b; return *this;}  
    BigInteger& operator -= (const BigInteger& b) {*this = *this - b; return *this;}  
    BigInteger& operator *= (const BigInteger& b) {*this = *this * b; return *this;}  
    BigInteger& operator /= (const BigInteger& b) {*this = *this / b; return *this;}  
    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 b < *this || *this < b;}  
    bool operator==(const BigInteger& b) const{return !(b < *this) && !(b > *this);}  
};  
      
ostream& operator << (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;  
}  
      
istream& operator >> (istream& in, BigInteger& x) {  
    string s;  
    if (!(in >> s)) return in;  
    x = s;  return in;  
}


介绍-1:基本模板 (bign=BigInteger)

说明:注释出现的“[int]”形式,代表这是int类型的变量名或者一个int值。其它[bign]、[char*]同理。

    #include <iostream> // 要用cin、cout   
    #include <string>   // 要用string类   
    #include <cstring>  // 要用strlen   
    #include <cstdio>   // 要用sprintf   
    using namespace std;  
      
    const int maxn = 2000;  // 大整数的最高位数限制   
      
    struct bign{  
        int d[maxn], len;  
      
        // 去掉大数的前导0   
        void clean() { while(len > 1 && !d[len-1]) len--; }  
      
        // 初始化:默认初始化为值0   
        bign() { memset(d, 0, sizeof(d)); len = 1; }  
          
        // 初始化:可以用“bign [bign] = [int];”或“bign [bign]([int]);”  
        bign(int num) { *this = num; }  
          
        // 初始化:可以用“bign [bign] = [char*];”或“bign [bign](char*);”  
        bign(char* num) { *this = num; }  
          
        // 赋值:可以用“[bign] = [char*];”   
        bign operator = (const char* num){  
            len = strlen(num);  
            for(int i = 0; i < len; i++) d[i] = num[len-1-i] - '0';  
            clean();  
            return *this;  
        }  
          
        // 赋值:可以用“[bign] = [int];”   
        bign operator = (int num){  
            char s[maxn];  
            sprintf(s, "%d", num);  
            *this = s;  
            return *this;  
        }  
      
        // 将int数组存储的值转换为高精度的字符串形式   
        string str() const{  
            string res;  
            for(int i = 0; i < len; i++) res = char(d[i]+'0') + res;  
            return res;  
        }  
    };  
      
    // 可以用“cin >> [bign];”的方式输入   
    istream& operator >> (istream& in, bign& x)  
    {  
        string s;  
        in >> s;  
        x = s.c_str();  
        return in;  
    }  
      
    // 可以用“cout << [bign];”的方式输出   
    ostream& operator << (ostream& out, const bign& x)  
    {  
        out << x.str();  
        return out;  
    }  

不论做哪类高精度运算最好都完整抄录该部分代码,可以让bign类型用起来跟int一样方便。

四个头文件包含了模板中需要用到的数据类型和函数。

常量maxn代表会出现的最大整数位数,这个值定太小会出错,但也不要太大浪费过多内存。

clean在后续的减法、乘法、除法里都要用到。


介绍-2:扩展bign的运算功能

该部分代码包括上面所有重载的运算符:+、-、*、/、%、+=。

模板的减法要注意不能用小数减大数,要算绝对值,可以用(a<b?b-a:a-b)。

虽然重载的运算符两边数据类型都是bign,但因为自动强制转换,所以用“[bign]*[int]”也不会错。

(这在应用中带来了相当大的便利)   

这里的除法与C语言中两个整数相除的效果相同,会舍尾取整。且除法里其实包含取余运算了,最后的a就是。

末尾写了个重载“+=”的代码,主要是方便bign类型的使用。读者可以根据自己喜好,

①把“*=”等的重载代码写上方便使用,②或者在使用bign类型中不要用这类运算符。

最后说一下效率问题,因为我的代码可以进行大数对大数的运算,如大数除大数、大数对大数取余,

所以在大数除int、大数对int取余时,效率不及专门功能的函数,这里牺牲效率增加通用性。


介绍-3:扩展bign的比较功能
        只要定义了“<”符号,即可用它定义其他所有比较运算符。实际题目中根据需要抄录小于和其它需要的运算符,不必全部写入(虽然到了高级运算,如取余,就环环相扣,很难删除某一部分了),在“介绍-2”中的运算符也是一样,这样在ACM比赛中能加快解题速度。




猜你喜欢

转载自blog.csdn.net/flora715/article/details/80496700