oi-wiki
Version:
wiki for OI / ACM-ICPC
221 lines (212 loc) • 4.94 kB
Markdown
什么时候需要高精度呢?就比如数据规模很大,unsigned long long 都存不下,就需要开一个字符数组来准确地表示一个数。
高精度问题包含很多小的细节,实现上也有很多讲究,暂时先不展开。
- 四则运算
- 快速幂
- 分数
- 对数(?)
- 开根
- 压位高精度
放一个之前的高精度板子吧。
还有一个很好用的[高精度封装类](https://paste.ubuntu.com/p/7VKYzpC7dn/) 10kb 想用可以自行下载。
```c++
//MAXN 是一位中最大的数字
//MAXSIZE 是位数
//DLEN 记录压几位
struct Big{
int a[MAXSIZE],len;
bool flag;//标记符号'-'
Big(){len = 1;memset(a,0,sizeof a);flag = 0;}
Big(const int);
Big(const char*);
Big(const Big&);
Big &operator = (const Big &);//注意这里operator有&,因为赋值有修改……
//由于OI中要求效率
//此处不使用泛型函数
//故不重载
//istream& operator>>(istream&, BigNum&); //重载输入运算符
//ostream& operator<<(ostream&, BigNum&); //重载输出运算符
Big operator + (const Big &)const;
Big operator - (const Big &)const;
Big operator * (const Big &)const;
Big operator / (const int &)const;
//TODO: Big / Big;
Big operator ^ (const int &)const;
//TODO: Big ^ Big;
//TODO: Big 位运算;
int operator % (const int &)const;
//TODO: Big ^ Big;
bool operator < (const Big &)const;
bool operator < (const int &t)const;
inline void print();
};
//README::不要随随便便把参数都变成引用,那样没办法传值
Big::Big(const int b){
int c,d = b;
len = 0;
// memset(a,0,sizeof a);
CLR(a);
while (d > MAXN){
c = d - (d / (MAXN + 1) * (MAXN + 1));
d = d / (MAXN + 1);
a[len++] = c;
}
a[len++] = d;
}
Big::Big(const char* s){
int t,k,index,l;
CLR(a);
l = strlen(s);
len = l / DLEN;
if (l % DLEN)++len;
index = 0;
for(int i = l - 1;i >= 0;i -= DLEN){
t = 0;
k = i - DLEN + 1;
if (k < 0)k = 0;
g(j,k,i)t = t * 10 + s[j] - '0';
a[index++] = t;
}
}
Big::Big(const Big& T):len(T.len){
CLR(a);
f(i,0,len)a[i] = T.a[i];
// TODO:重载此处?
}
Big& Big::operator = (const Big& T){
CLR(a);
len = T.len;
f(i,0,len)a[i] = T.a[i];
return *this;
}
Big Big::operator + (const Big& T)const{
Big t(*this);
int big = len;
if (T.len > len)big = T.len;
f(i,0,big){
t.a[i] += T.a[i];
if (t.a[i] > MAXN){
++t.a[i + 1];
t.a[i] -= MAXN + 1;
}
}
if (t.a[big])t.len = big + 1;
else t.len = big;
return t;
}
Big Big::operator - (const Big& T)const{
int big;
bool ctf;
Big t1,t2;
if (*this < T){
t1 = T;
t2 = *this;
ctf = 1;
}else {
t1 =*this;
t2 = T;
ctf = 0;
}
big = t1.len;
int j = 0;
f(i,0,big){
if (t1.a[i] < t2.a[i]){
j = i + 1;
while (t1.a[j] == 0)++j;
--t1.a[j--];
//WTF?
while (j > i)t1.a[j--] += MAXN;
t1.a[i] += MAXN + 1 - t2.a[i];
}else t1.a[i] -= t2.a[i];
}
t1.len = big;
while (t1.len > 1 && t1.a[t1.len - 1] == 0){
--t1.len;
--big;
}
if (ctf)t1.a[big - 1] = -t1.a[big - 1];
return t1;
}
Big Big::operator * (const Big& T)const{
Big res;
int up;
int te,tee;
f(i,0,len){
up = 0;
f(j,0,T.len){
te = a[i] * T.a[j] + res.a[i + j] + up;
if (te > MAXN){
tee = te - te / (MAXN + 1) * (MAXN + 1);
up = te / (MAXN + 1);
res.a[i + j] = tee;
}else {
up = 0;
res.a[i + j] = te;
}
}
if (up)res.a[i + T.len] = up;
}
res.len = len + T.len;
while (res.len > 1 && res.a[res.len - 1] == 0)--res.len;
return res;
}
Big Big::operator / (const int& b)const{
Big res;
int down = 0;
gd(i,len - 1,0){
res.a[i] = (a[i] + down * (MAXN + 1) / b);
down = a[i] + down * (MAXN + 1) - res.a[i] * b;
}
res.len = len;
while (res.len > 1 && res.a[res.len - 1] == 0)--res.len;
return res;
}
int Big::operator % (const int& b)const {
int d = 0;
gd(i,len - 1,0)d = (d * (MAXN + 1) % b + a[i]) % b;
return d;
}
Big Big::operator ^ (const int& n)const{
Big t(n),res(1);
//TODO::快速幂这样写好丑= =//DONE:)
int y = n;
while (y){
if (y & 1)res = res * t;
t = t * t;
y >>= 1;
}
return res;
}
bool Big::operator < (const Big& T)const {
int ln;
if (len < T.len)return 233;
if (len == T.len){
ln = len - 1;
while (ln >= 0 && a[ln] == T.a[ln])--ln;
if (ln >= 0 && a[ln] < T.a[ln])return 233;
return 0;
}
return 0;
}
inline bool Big::operator < (const int &t)const{
Big tee(t);
return *this < tee;
}
inline void Big::print(){
printf("%d",a[len - 1]);
gd(i,len - 2,0){
printf("%04d",a[i]);
}
}
inline void print(Big s){
//s不要是引用,要不然你怎么print(a * b);
int len = s.len;
printf("%d",s.a[len - 1]);
gd(i,len - 2,0){
printf("%04d",s.a[i]);
}
}
char s[100024];
```