C++高精度模板

原文地址:http://blog.csdn.net/wall_f/article/details/8373395

原文只附代码,没有解析,本文增加了一些对代码的解释

请注意:本模板不涉及实数运算与负数运算,使用减法a-b时请保证, a >= b;所有用本模板来转化的数需保证a >0 && a无小数部分。


引:
题目中涉及到高精度运算在信息学竞赛中并不少见,很多题目得不到全分就是因为选手不会写高精度模板。尽管AC过高精度(+,*,-,//除法麻烦一点)模板题,但是对于将高精度写入结构体使得可以正常运算的bign模板,很多选手只是有所听闻而不会写。其实写起来并不难,只是将原来那些模板题写入运算符重载即可

建议背下来,OI比赛中指不定就撞上了,现推也可以,但是比较慢,至少保证熟练

运算涉及
Bool型:== 、> 、< 、 >= 、 <= 、 !=
赋值语句:= 、 +=、 -=、 *=、 /=、 %=
运算符:+ 、- 、 * 、 /、 %

其中 (?)= 赋值运算符的重载最为好写,直接调用已经重载完成的(?)运算符,再返回当前this。(? includes + - / %)

其次便是bool型。> < 分别用字符串的比较的比较方式重载,其余的只需要将它们组合一下。例如 == : !(>) && !(<)。

难点在于除法运算符的重载

我们定义一个结构体包含一个整型int(长度)与数组s(存每一位)组成,其中数组是反着存的。


#include <bits/stdc++.h> 

using namespace std;

const int MAXN = 5005;  

struct bign  
{  
    int len, s[MAXN];  
    bign ()  //初始化
    {  
        memset(s, 0, sizeof(s));  
        len = 1;  
    }  
    bign (int num) { *this = num; }  
    bign (const char *num) { *this = num; }  //让this指针指向当前字符串
    bign operator = (const int num)  
    {  
        char s[MAXN];  
        sprintf(s, "%d", num);  //sprintf函数将整型映到字符串中
        *this = s;  
        return *this;  //再将字符串转到下面字符串转化的函数中
    }  
    bign operator = (const char *num)  
    {  
        for(int i = 0; num[i] == '0'; num++) ;  //去前导0  
        len = strlen(num);  
        for(int i = 0; i < len; i++) s[i] = num[len-i-1] - '0'; //反着存
        return *this;
    }  
    bign operator + (const bign &b) const //对应位相加,最为简单
    {  
        bign c;  
        c.len = 0;  
        for(int i = 0, g = 0; g || i < max(len, b.len); i++)  
        {  
            int x = g;  
            if(i < len) x += s[i];  
            if(i < b.len) x += b.s[i];  
            c.s[c.len++] = x % 10;  //关于加法进位
            g = x / 10;  
        }  
        return c;  
    }  
    bign operator += (const bign &b)  //如上文所说,此类运算符皆如此重载
    {  
        *this = *this + b;  
        return *this;  
    }  
    void clean()  //由于接下来的运算不能确定结果的长度,先大而估之然后再查
    {  
        while(len > 1 && !s[len-1]) len--;  //首位部分‘0’故删除该部分长度
    }   
    bign operator * (const bign &b) //乘法重载在于列竖式,再将竖式中的数转为抽象,即可看出运算法则。
    {  
        bign c;  
        c.len = len + b.len;  
        for(int i = 0; i < len; i++)  
        {  
            for(int j = 0; j < b.len; j++)  
            {  
                c.s[i+j] += s[i] * b.s[j];//不妨列个竖式看一看
            }  
        }  
        for(int i = 0; i < c.len; i++) //关于进位,与加法意同 
        {  
            c.s[i+1] += c.s[i]/10;
            c.s[i] %= 10;
        }  
        c.clean();  //我们估的位数是a+b的长度和,但可能比它小(1*1 = 1)
        return c;  
    }  
    bign operator *= (const bign &b)  
    {  
        *this = *this * b;  
        return *this;  
    }  
    bign operator - (const bign &b)  //对应位相减,加法的进位改为借1
    {  //不考虑负数
        bign c;  
        c.len = 0;  
        for(int i = 0, g = 0; i < len; i++)  
        {  
            int x = s[i] - g;  
            if(i < b.len) x -= b.s[i];  //可能长度不等
            if(x >= 0) g = 0;  //是否向上移位借1
            else  
            {  
                g = 1;  
                x += 10;  
            }  
            c.s[c.len++] = x;  
        }  
        c.clean();  
        return c;   
    }  
    bign operator -= (const bign &b)  
    {  
        *this = *this - b;  
        return *this;  
    }  
    bign operator / (const bign &b)  //运用除是减的本质,不停地减,直到小于被减数
    {  
        bign c, f = 0; //可能会在使用减法时出现高精度运算 
        for(int i = len-1; i >= 0; i--)  //正常顺序,从最高位开始
        {  
            f = f*10;  //上面位的剩余到下一位*10
            f.s[0] = s[i];  //加上当前位
            while(f >= b)  
            {  
                f -= b;  
                c.s[i]++;  
            }  
        }  
        c.len = len;  //估最长位
        c.clean();  
        return c;  
    }  
    bign operator /= (const bign &b)  
    {  
        *this  = *this / b;  
        return *this;  
    }  
    bign operator % (const bign &b)  //取模就是除完剩下的
    {  
        bign r = *this / b;  
        r = *this - r*b;  
        r.clean();
        return r;  
    }  
    bign operator %= (const bign &b)  
    {  
        *this = *this % b;  
        return *this;  
    }  
    bool operator < (const bign &b) //字符串比较原理 
    {  
        if(len != b.len) return len < b.len;  
        for(int i = len-1; i != -1; i--)  
        {  
            if(s[i] != b.s[i]) return s[i] < b.s[i];  
        }  
        return false;  
    }  
    bool operator > (const bign &b)  //同理
    {  
        if(len != b.len) return len > b.len;  
        for(int i = len-1; i != -1; i--)  
        {  
            if(s[i] != b.s[i]) return s[i] > b.s[i];  
        }  
        return false;  
    }  
    bool operator == (const bign &b)  
    {  
        return !(*this > b) && !(*this < b);  
    }  
    bool operator != (const bign &b)  
    {  
        return !(*this == b);  
    }  
    bool operator <= (const bign &b)  
    {  
        return *this < b || *this == b;  
    }  
    bool operator >= (const bign &b)  
    {  
        return *this > b || *this == b;  
    }  
    string str() const  //将结果转化为字符串(用于输出)
    {  
        string res = "";  
        for(int i = 0; i < len; i++) res = char(s[i]+'0')+res;  
        return res;  
    }  
};  

istream& operator >> (istream &in, bign &x) //重载输入流 
{  
    string s;  
    in >> s;  
    x = s.c_str();  //string转化为char[]
    return in;  
}  

ostream& operator << (ostream &out, const bign &x)  //重载输出流
{  
    out << x.str();  
    return out;  
}

int main()
{
    bign a;//除了声明外其他如整型般使用
    //……
    return 0;
}

感谢原作者。

不妨运用一下:
luogu P1601 A+B Problem(高精) https://www.luogu.org/problem/show?pid=1601
luogu P2142 高精度减法 https://www.luogu.org/problem/show?pid=2142
luogu P1303 A*B Problem https://www.luogu.org/problem/show?pid=1303
luogu P1480 A/B Problem https://www.luogu.org/problem/show?pid=1480

不妨思考一下其他高精度运算:
luogu:P2293 [HNOI2004]高精度开根 https://www.luogu.org/problem/show?pid=2293

高精度模板至此结束。
箜瑟_qi 2017.04.08 9:53

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
精度算法是指能够处理超出计算机基本数据类型范围的数字运算问题的算法。常见的精度算法有大整数加减乘除、精度开方、精度取模等。 以下是acwing的精度算法模板: 1. 大整数加法 C++ 代码: vector<int> add(vector<int> &A, vector<int> &B) { vector<int> C; int t = 0; for (int i = 0; i < A.size() || i < B.size(); i++) { if (i < A.size()) t += A[i]; if (i < B.size()) t += B[i]; C.push_back(t % 10); t /= 10; } if (t) C.push_back(1); return C; } 2. 大整数减法 C++ 代码: bool cmp(vector<int> &A, vector<int> &B) { if (A.size() != B.size()) return A.size() > B.size(); for (int i = A.size() - 1; i >= 0; i--) { if (A[i] != B[i]) return A[i] > B[i]; } return true; } vector<int> sub(vector<int> &A, vector<int> &B) { vector<int> C; for (int i = 0, t = 0; i < A.size(); i++) { t = A[i] - t; if (i < B.size()) t -= B[i]; C.push_back((t + 10) % 10); if (t < 0) t = 1; else t = 0; } while (C.size() > 1 && C.back() == 0) C.pop_back(); return C; } 3. 大整数乘法 C++ 代码: vector<int> mul(vector<int> &A, int b) { vector<int> C; int t = 0; for (int i = 0; i < A.size() || t; i++) { if (i < A.size()) t += A[i] * b; C.push_back(t % 10); t /= 10; } return C; } vector<int> mul(vector<int> &A, vector<int> &B) { vector<int> C(A.size() + B.size(), 0); for (int i = 0; i < A.size(); i++) { int t = 0; for (int j = 0; j < B.size() || t; j++) { if (j < B.size()) t += A[i] * B[j]; t += C[i + j]; C[i + j] = t % 10; t /= 10; } } while (C.size() > 1 && C.back() == 0) C.pop_back(); return C; } 4. 大整数除法 C++ 代码: int cmp(vector<int> &A, vector<int> &B) { if (A.size() != B.size()) return A.size() < B.size() ? -1 : 1; for (int i = A.size() - 1; i >= 0; i--) { if (A[i] != B[i]) return A[i] < B[i] ? -1 : 1; } return 0; } vector<int> div(vector<int> &A, int b, int &r) { vector<int> C; r = 0; for (int i = A.size() - 1; i >= 0; i--) { r = r * 10 + A[i]; C.push_back(r / b); r %= b; } reverse(C.begin(), C.end()); while (C.size() > 1 && C.back() == 0) C.pop_back(); return C; } vector<int> div(vector<int> &A, vector<int> &B) { vector<int> C; for (int i = A.size() - 1; i >= 0; i--) { C.insert(C.begin(), A[i]); while (cmp(C, B) >= 0) { vector<int> t = sub(C, B); C = t; } } while (C.size() > 1 && C.back() == 0) C.pop_back(); return C; } 5. 精度开方 C++ 代码: int cmp(vector<int> &A, vector<int> &B) { if (A.size() != B.size()) return A.size() < B.size() ? -1 : 1; for (int i = A.size() - 1; i >= 0; i--) { if (A[i] != B[i]) return A[i] < B[i] ? -1 : 1; } return 0; } vector<int> sqrt(vector<int> &A) { vector<int> C; if (A.size() % 2 == 1) A.push_back(0); for (int i = A.size() - 2; i >= 0; i -= 2) { int res = 0; for (int j = 9; j >= 0; j--) { vector<int> t = mul(C, 20); t.push_back(j * j); if (cmp(t, A) <= 0) { res = j; C.push_back(j); break; } } } reverse(C.begin(), C.end()); while (C.size() > 1 && C.back() == 0) C.pop_back(); return C; } 6. 精度取模 C++ 代码: int mod(vector<int> &A, int b) { int r = 0; for (int i = A.size() - 1; i >= 0; i--) { r = r * 10 + A[i]; r %= b; } return r; } vector<int> mod(vector<int> &A, vector<int> &B) { vector<int> C; for (int i = A.size() - 1; i >= 0; i--) { C.insert(C.begin(), A[i]); while (cmp(C, B) >= 0) { vector<int> t = sub(C, B); C = t; } } return C; }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值