原文地址:http://blog.csdn.net/wall_f/article/details/8373395c++
原文只附代碼,沒有解析,本文增長了一些對代碼的解釋。算法
請注意:本模板不涉及實數運算與負數運算,使用減法a-b時請保證, a >= b;全部用本模板來轉化的數需保證a >0 && a無小數部分。數組
引:
題目中涉及到高精度運算在信息學競賽中並很多見,不少題目得不到全分就是由於選手不會寫高精度模板。儘管AC太高精度(+,*,-,//除法麻煩一點)模板題,可是對於將高精度寫入結構體使得能夠正常運算的bign模板,不少選手只是有所聽聞而不會寫。其實寫起來並不難,只是將原來那些模板題寫入運算符重載便可 。markdown
建議背下來,OI比賽中指不定就撞上了,現推也能夠,可是比較慢,至少保證熟練。函數
運算涉及:
Bool型:== 、> 、< 、 >= 、 <= 、 !=
賦值語句:= 、 +=、 -=、 *=、 /=、 %=
運算符:+ 、- 、 * 、 /、 %this
其中 (?)= 賦值運算符的重載最爲好寫,直接調用已經重載完成的(?)運算符,再返回當前this。(? includes + - / %)spa
其次即是bool型。> < 分別用字符串的比較的比較方式重載,其他的只須要將它們組合一下。例如 == : !(>) && !(<)。.net
難點在於除法運算符的重載。指針
咱們定義一個結構體包含一個整型int(長度)與數組s(存每一位)組成,其中數組是反着存的。code
#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