原文地址: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

05-11 15:08