目录:(内容正在逐步完善)
-- 存储
-- 四则运算
-- 快速幂
-- 分数
-- 对数(?)
-- 开根
-- 压位高精度
+- 存储
+- 四则运算
+- 快速幂
+- 分数
+- 对数(?)
+- 开根
+- 压位高精度
还有一个很好用的[高精度封装类](https://paste.ubuntu.com/p/7VKYzpC7dn/) 10kb 想用可以自行下载。
```c++
#define MAXN 9999
-//MAXN 是一位中最大的数字
+// MAXN 是一位中最大的数字
#define MAXSIZE 10024
-//MAXSIZE 是位数
+// MAXSIZE 是位数
#define DLEN 4
-//DLEN 记录压几位
-struct Big{
- int a[MAXSIZE],len;
- bool flag;//标记符号'-'
- Big(){len = 1;memset(a,0,sizeof a);flag = 0;}
+// 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有&,因为赋值有修改……
+ 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;
+ // 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;
+// README::不要随随便便把参数都变成引用,那样没办法传值
+Big::Big(const int b) {
+ int c, d = b;
len = 0;
// memset(a,0,sizeof a);
CLR(a);
- while (d > MAXN){
+ 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;
+Big::Big(const char* s) {
+ int t, k, index, l;
CLR(a);
l = strlen(s);
len = l / DLEN;
- if (l % DLEN)++len;
+ if (l % DLEN) ++len;
index = 0;
- for(int i = l - 1;i >= 0;i -= DLEN){
+ 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';
+ 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){
+Big::Big(const Big& T) : len(T.len) {
CLR(a);
- f(i,0,len)a[i] = T.a[i];
-// TODO:重载此处?
+ f(i, 0, len) a[i] = T.a[i];
+ // TODO:重载此处?
}
-Big& Big::operator = (const Big& T){
+Big& Big::operator=(const Big& T) {
CLR(a);
len = T.len;
- f(i,0,len)a[i] = T.a[i];
+ f(i, 0, len) a[i] = T.a[i];
return *this;
}
-Big Big::operator + (const Big& T)const{
+Big Big::operator+(const Big& T) const {
Big t(*this);
int big = len;
- if (T.len > len)big = T.len;
- f(i,0,big){
+ if (T.len > len) big = T.len;
+ f(i, 0, big) {
t.a[i] += T.a[i];
- if (t.a[i] > MAXN){
+ 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;
+ if (t.a[big])
+ t.len = big + 1;
+ else
+ t.len = big;
return t;
}
-Big Big::operator - (const Big& T)const{
+Big Big::operator-(const Big& T) const {
int big;
bool ctf;
- Big t1,t2;
- if (*this < T){
+ Big t1, t2;
+ if (*this < T) {
t1 = T;
t2 = *this;
ctf = 1;
- }else {
- t1 =*this;
+ } else {
+ t1 = *this;
t2 = T;
ctf = 0;
}
big = t1.len;
int j = 0;
- f(i,0,big){
- if (t1.a[i] < t2.a[i]){
+ f(i, 0, big) {
+ if (t1.a[i] < t2.a[i]) {
j = i + 1;
- while (t1.a[j] == 0)++j;
+ while (t1.a[j] == 0) ++j;
--t1.a[j--];
- //WTF?
- while (j > i)t1.a[j--] += MAXN;
+ // WTF?
+ while (j > i) t1.a[j--] += MAXN;
t1.a[i] += MAXN + 1 - t2.a[i];
- }else t1.a[i] -= t2.a[i];
+ } else
+ t1.a[i] -= t2.a[i];
}
t1.len = big;
- while (t1.len > 1 && t1.a[t1.len - 1] == 0){
+ while (t1.len > 1 && t1.a[t1.len - 1] == 0) {
--t1.len;
--big;
}
- if (ctf)t1.a[big - 1] = -t1.a[big - 1];
+ if (ctf) t1.a[big - 1] = -t1.a[big - 1];
return t1;
}
-Big Big::operator * (const Big& T)const{
+Big Big::operator*(const Big& T) const {
Big res;
int up;
- int te,tee;
- f(i,0,len){
+ int te, tee;
+ f(i, 0, len) {
up = 0;
- f(j,0,T.len){
+ f(j, 0, T.len) {
te = a[i] * T.a[j] + res.a[i + j] + up;
- if (te > MAXN){
+ if (te > MAXN) {
tee = te - te / (MAXN + 1) * (MAXN + 1);
up = te / (MAXN + 1);
res.a[i + j] = tee;
- }else {
+ } else {
up = 0;
res.a[i + j] = te;
}
}
- if (up)res.a[i + T.len] = up;
+ 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;
+ while (res.len > 1 && res.a[res.len - 1] == 0) --res.len;
return res;
}
-Big Big::operator / (const int& b)const{
+Big Big::operator/(const int& b) const {
Big res;
int down = 0;
- gd(i,len - 1,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;
+ while (res.len > 1 && res.a[res.len - 1] == 0) --res.len;
return res;
}
-int Big::operator % (const int& b)const {
+int Big::operator%(const int& b) const {
int d = 0;
- gd(i,len - 1,0)d = (d * (MAXN + 1) % b + a[i]) % b;
+ 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:)
+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;
+ while (y) {
+ if (y & 1) res = res * t;
t = t * t;
y >>= 1;
}
return res;
}
-bool Big::operator < (const Big& T)const {
+bool Big::operator<(const Big& T) const {
int ln;
- if (len < T.len)return 233;
- if (len == T.len){
+ 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;
+ 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{
+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 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);
+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]);
- }
+ printf("%d", s.a[len - 1]);
+ gd(i, len - 2, 0) { printf("%04d", s.a[i]); }
}
char s[100024];
```
高精度的存储其实非常简单。首先,我们读进去一个字符串,然后倒序将每一位存贮在数组内,每一位数对应一个下标。
-倒序存储是有原因的。当计算机读进来字符串时,第一位是最高位。为了方便计算,我们需要将最低位存储在1位。
+倒序存储是有原因的。当计算机读进来字符串时,第一位是最高位。为了方便计算,我们需要将最低位存储在 1 位。
-下面给一份C++代码:
+下面给一份 C++ 代码:
```c++
-char aa[MAXLEN],bb[MAXLEN];
-int a[MAXLEN],b[MAXLEN];
-int lena,lenb,len;
-void read()
-{
- cin>>aa>>bb;
- lena=strlen(aa);
- lenb=strlen(bb);
- len=max(lena,lenb);//这一步在部分高精运算中可有可无
- for (int i=0;i<lena;i++)
- a[lena-i]=aa[i]-'0';//好好理解这一步
- for (int i=0;i<lenb;i++)
- b[lenb-i]=bb[i]-'0';
+char aa[MAXLEN], bb[MAXLEN];
+int a[MAXLEN], b[MAXLEN];
+int lena, lenb, len;
+void read() {
+ cin >> aa >> bb;
+ lena = strlen(aa);
+ lenb = strlen(bb);
+ len = max(lena, lenb); //这一步在部分高精运算中可有可无
+ for (int i = 0; i < lena; i++) a[lena - i] = aa[i] - '0'; //好好理解这一步
+ for (int i = 0; i < lenb; i++) b[lenb - i] = bb[i] - '0';
}
```
-
-
## 四则运算
-四则运算是最简单的内容,也是学习OI必备的内容之一。
+四则运算是最简单的内容,也是学习 OI 必备的内容之一。
-四则运算中难度也各不相同。最简单的是`高精度+高精度`,然后是`高精度*高精度`,其次是`高精度-高精度`,最后是`高精度/高精度`。我们先从简单的开始看起。
+四则运算中难度也各不相同。最简单的是`高精度 + 高精度`,然后是`高精度 * 高精度`,其次是`高精度 - 高精度`,最后是`高精度 / 高精度`。我们先从简单的开始看起。
### 加法
加法非常简单,一位一位地加即可。
-在进位时,我们需要看一看该位($a_i$)有没有超过10,如果超过了,那么$c_{i+1}=c_{i+1}+1,c_i=c_i\mod 10$即可。
+在进位时,我们需要看一看该位($a_i$)有没有超过 10,如果超过了,那么$c_{i+1}=c_{i+1}+1,c_i=c_i\mod 10$即可。
代码如下:
```c++
-char aa[MAXLEN],bb[MAXLEN];
-int a[MAXLEN],b[MAXLEN],c[MAXLEN];
-int lena,lenb,len;
-void plus()
-{
- read();
- for (int i=1;i<=len;i++)
+char aa[MAXLEN], bb[MAXLEN];
+int a[MAXLEN], b[MAXLEN], c[MAXLEN];
+int lena, lenb, len;
+void plus() {
+ read();
+ for (int i = 1; i <= len; i++) {
+ c[i] = a[i] + b[i];
+ if (c[i] >= 10) //进位
{
- c[i]=a[i]+b[i];
- if (c[i]>=10)//进位
- {
- c[i+1]++;
- c[i]=c[i]%10;
- }
+ c[i + 1]++;
+ c[i] = c[i] % 10;
}
- if (len+1!=0)//如果最后一位有进位
- len++;
- while (c[len]==0)//压前导0
- len--;
- for (int i=len;i>=1;i--)//从最高位输出
- cout<<c[i];
+ }
+ if (len + 1 != 0) //如果最后一位有进位
+ len++;
+ while (c[len] == 0) //压前导0
+ len--;
+ for (int i = len; i >= 1; i--) //从最高位输出
+ cout << c[i];
}
```
![](./images/multiplication.png)
通过观察我们发现有如下的计算规律:
+
$$
c_{i+j-1}=a_i*b_j
$$
-(其中,$c_{i+j-1}$代表答案的第$i+j-1$位,$a_i$代表第一个数的第i位,$b_j$代表第二个数的第j位。该公式对于任何有效的i和j均有效。)
+
+(其中,$c_{i+j-1}$代表答案的第$i+j-1$位,$a_i$代表第一个数的第 i 位,$b_j$代表第二个数的第 j 位。该公式对于任何有效的 i 和 j 均有效。)
进位也比较容易:
+
$$
c_{i+1}=c_{i+1}+c_i \div 10,c_i=c_i\mod 10
$$
+
(其中,除号为整除运算)
-乘法运算的下标不能从0开始,为什么呢?因为$0+0-1=-1$,这一点需要特别注意。
+乘法运算的下标不能从 0 开始,为什么呢?因为$0+0-1=-1$,这一点需要特别注意。
代码如下:
```c++
-char aa[MAXLEN],bb[MAXLEN];
-int a[MAXLEN],b[MAXLEN],c[MAXLEN];
-int lena,lenb,len;
-void mul()
-{
- read();
- for (int i=1;i<=lena;i++)
- for (int j=1;j<=lenb;j++)
- c[i+j-1]=a[i]*b[j];
- int i;
- for (i=1;c[i]!=0||i<=len;i++)//进位
- if (c[i]>=10)
- {
- c[i+1]+=c[i]/10;
- c[i]%=10;
- }
- len=i;
- while (c[len]==0)//压前导零
- len--;
- for (int i=len;i>=1;i--)//从最高位输出
- cout<<c[i];
+char aa[MAXLEN], bb[MAXLEN];
+int a[MAXLEN], b[MAXLEN], c[MAXLEN];
+int lena, lenb, len;
+void mul() {
+ read();
+ for (int i = 1; i <= lena; i++)
+ for (int j = 1; j <= lenb; j++) c[i + j - 1] = a[i] * b[j];
+ int i;
+ for (i = 1; c[i] != 0 || i <= len; i++) //进位
+ if (c[i] >= 10) {
+ c[i + 1] += c[i] / 10;
+ c[i] %= 10;
+ }
+ len = i;
+ while (c[len] == 0) //压前导零
+ len--;
+ for (int i = len; i >= 1; i--) //从最高位输出
+ cout << c[i];
}
```
我们发现一个特点:$a-b=-(b-a)$。
举个例子:
+
$$
1-2=-1
,
,
-(2-1)=-1
$$
-所以,我们遇到$a<b$的情况,我们需要先输出“-”再交换两数,接着进行减法计算。
+
+所以,我们遇到$a<b$的情况,我们需要先输出 “-” 再交换两数,接着进行减法计算。
否则直接进行计算即可。
代码如下:
```c++
-char aa[MAXLEN],bb[MAXLEN];
-int a[MAXLEN],b[MAXLEN],c[MAXLEN];
-int lena,lenb,len;
-void sub()
-{
- read();
- bool flag=false;
- for (int i=len;i>=1;i--)//判断是否出现a<b的情况
- if (a[i]<b[i])
- flag=true;
- if (flag)
- {
- int tmp[MAXLEN];
- for (int i=1;i<=len;i++)//交换两数
- tmp[i]=a[i];
- for (int i=1;i<=len;i++)
- a[i]=b[i];
- for (int i=1;i<=len;i++)
- b[i]=tmp[i];
- cout<<"-";//输出负号
- }
- for (int i=1;i<=len;i++)
- {
- if (a[i]-b[i]<0)
- {
- a[i]+=10;
- a[i+1]--;
- }
- c[i]=a[i]-b[i];
+char aa[MAXLEN], bb[MAXLEN];
+int a[MAXLEN], b[MAXLEN], c[MAXLEN];
+int lena, lenb, len;
+void sub() {
+ read();
+ bool flag = false;
+ for (int i = len; i >= 1; i--) //判断是否出现a<b的情况
+ if (a[i] < b[i]) flag = true;
+ if (flag) {
+ int tmp[MAXLEN];
+ for (int i = 1; i <= len; i++) //交换两数
+ tmp[i] = a[i];
+ for (int i = 1; i <= len; i++) a[i] = b[i];
+ for (int i = 1; i <= len; i++) b[i] = tmp[i];
+ cout << "-"; //输出负号
+ }
+ for (int i = 1; i <= len; i++) {
+ if (a[i] - b[i] < 0) {
+ a[i] += 10;
+ a[i + 1]--;
}
- while (c[len]==0)//压前导零
- len--;
- for (int i=len;i>=1;i--)//从最高位输出
- cout<<c[i];
+ c[i] = a[i] - b[i];
+ }
+ while (c[len] == 0) //压前导零
+ len--;
+ for (int i = len; i >= 1; i--) //从最高位输出
+ cout << c[i];
}
```
首先,两个指针,head、tail,初始都为最高位。
-这时,我们将$a_{head} a_{head-1} \dots a_{tail}$看为一个数(a为被除数,b为除数,c为商),对b进行减法运算,看看能做多少次,结果为$c_{tail}$的商,做完后,head++,重复直到无法继续运算。
+这时,我们将$a_{head} a_{head-1} \dots a_{tail}$看为一个数(a 为被除数,b 为除数,c 为商),对 b 进行减法运算,看看能做多少次,结果为$c_{tail}$的商,做完后,head++,重复直到无法继续运算。
## 更多内容未完待续……