高精度
这东西暂且归为数据结构吧
巨难写的东西,恶心死个人。(但用还是要用的)
说实话不常用,但是该用的时候还真没有能替代的。
正常C++,int类型最大长度为9位,longlong约为18位,就算是__int128也不过30多位
而有的时候,我们需要用到几百上千位,这时候就得用到高精度了。
它的中心思想是用字符串存下数,利用字符串模拟加减乘数的运算
但时代在进步,现在好像都用vector来存储大整数。
注意,高精度有一种缩短时间和空间的方法,叫压位,正常我们每个int只存1位数,但这样太浪费了,都知道int最大是9位,那么我们就让int存9位,这样就缩小了时间和空间。一般压8位而不压9位,为了防止以外爆炸,对于高精乘低精则更低
读入
一般利用字符串读入,然后用vector存起来。
注意一般是逆序转存,因为我们操作的时候是从最低位开始的
非压位
void read(string &s1, vector<int> &A)
{
for (int i = s1.size() - 1; i >= 0; i -- ) A.push_back(s1[i] - '0');
}
压位版
这玩意看看代码应该就明白了。
注意一点j == 9那里压多少位写多大的数
void read(string &s1, vector<int> &A)
{
for (int i = s1.size() - 1, t = 1, s = 0, j = 0; i >= 0; i -- )
{
s += (s1[i] - '0') * t;
j ++ , t *= 10;
if (j == 9 || i == 0)
{
A.push_back(s);
s = j = 0;
t = 1;
}
}
}
输出
注意逆序输入就要逆序输出
非压位
for (int i = C.size() - 1; i >= 0; i -- ) cout << C[i];
压位
压位版因为C的首位不确定长度所以要先输出来,
而在后面可能会遇到因取模而小于压位位数的情况,所以我们要用printf固定输出,空缺补0
cout << C.back();
for (int i = C.size() - 2; i >= 0; i -- ) printf("%09d", C.[i]);
高精加
高精加有两种,一种为高精加高精,一种为高精加低精,但是高精加低精更少用,所以这里只写高精乘高精。
注意不能存负数,鬼才想处理正负号
非压位和压位几乎没有区别,实质上都是压位版,只不过压1位就是不压而已。
非压位
vector<int> M_add(vector<int> A, vector<int> B)
{
if (A.size() < B.size()) return M_add(B, A);
vector<int> C;
int t = 0, len = A.size();
for (int i = 0; i < len; i ++ )
{
t += A[i];
if (i < B.size()) t += B[i];
C.push_back(t % 10);
t /= 10;
}
if (t) C.push_back(t);
return C;
}
压位
int base = 1000000000; // 压位数组
vector<int> M_add(vector<int> A, vector<int> B)
{
if (A.size() < B.size()) return M_add(B, A);
vector<int> C;
int t = 0, len = A.size();
for (int i = 0; i < len; i ++ )
{
t += A[i];
if (i < B.size()) t += B[i];
C.push_back(t % base);
t /= base;
}
if (t) C.push_back(t);
return C;
}
高精减
和高精加有所不同,注意不够减了借位。最多借base位
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;
int t = 0, len = A.size();
for (int i = 0; i < len; 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.back() == 0 && C.size() > 1) C.pop_back();
return C;
}
int main()
{
cin >> s1 >> s2;
for (int i = s1.size() - 1; i >= 0; i -- ) A.push_back(s1[i] - '0');
for (int i = s2.size() - 1; i >= 0; i -- ) B.push_back(s2[i] - '0');
if (cmp(A, B)) C = sub(A, B);
else C = sub(B, A), cout << '-';
for (int i = C.size() - 1; i >= 0; i -- ) cout << C[i];
return 0;
}
高精乘
高精乘高精不常用,实际上跟着思路也能写出来,但速度慢,而且难调
兴许哪天脑子用了写个高精除高精
高精乘低精
vector<int> M_mul(vector<int> A, int b)
{
vector<int> C;
int t = 0, len = A.size();
for (int i = 0; i < len || t; i ++ ) // 一定要把t搞干净
{
if (i < len) t += A[i] * b;
C.push_back(t % 10);
t /= 10;
}
while (C.back() == 0 && C.size() > 1) C.pop_back();
return C;
}
高精除
高精除低精简单,高精除高精困难,这里说个思路,高精除高精,化除为减是一个办法
vector<int> divi(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()); // C push进去的先是高位后是低位,为了输出的一致所以要逆序
while (C.size() > 1 && C.back() == 0) C.pop_back();
return C;
}
好久以前的高精除高精
#include<iostream>
#include<cstring>
using namespace std;
const int N=200010;
int a[N],b[N],n,m;
long long sum;
char s1[N],s2[N];
bool bol()
{
if (n!=m) return n>m;
for (int i=1;i<=n;i++)
if(a[i]!=b[i]) return a[i]>b[i];
return true;
}
void cut()
{
for (int i=1;i<=n||i<=m;i++)
{
a[i]-=b[i];
if (a[i]<0)
{
a[i+1]--;
a[i]+=10;
}
}
while(!a[n]&&n>1) n--;
sum++;
}
int main()
{
cin>>s1>>s2;
//n=s1.size();
// m=s2.size();
n=strlen(s1);
m=strlen(s2);
for (int i=1;i<=n;i++) a[i]=s1[n-i]-'0';
for (int i=1;i<=m;i++) b[i]=s2[m-i]-'0';
while (bol())
{
cut();
}
cout<<sum<<endl;
while (n) cout<<a[n--];
return 0;
}

浙公网安备 33010602011771号