高精度
用高精度处理很长很长的数字。
基本思想是压位, 压n位即用数组一个元素表示n位数(从右往左读)。(可以理解为10^n进制)
注意如果用结构体+vector来存储,操作前先将vector::clear(),因为会执行合成的构造函数。
如果压1位,则一般从a[1]开始存,a[0]表示长度。很好用。
用字符串来读取数据再用结构体或直接用普通数组来存储。
四则运算则一般通过模拟竖式解决。
进位可以当成10^n进制来想。
但高精度除以高精度(高精度mod高精度)有点例外,下面再讲。
压n位存储
从右往左,每次截取n位。保险起见用long long来存
存储整型
从右往左,每一位读取num % 10^n,然后num /= 10^n。
存储字符串
算范围:
- start=str.length - i * WIDTH;
- end=max(0,end - WIDTH);
相关api:
- sscanf(cstring,”%ll”,&x): 将cstring存储到整型变量x中
- string::substr(start, end): 截取范围[start, end]的字符串。
输出
相关api
- ssprintf(cstrinig,”%08d”,x): 以宽度为8把整型n存到cstring中,向右对齐补0.
注意
- 首位可能不足n位,所以一般先将首位输出,再输出其余位。
- 前导零。
- 输出零。(-0)
高精度 / 高精度
一般思路是通过减法实现,求被除数减去除数能够减多少次。
有一种更高效的方法:
补“0”法(来自: 洛谷yejichen)
此法不同于一般的模拟(竖式法),除法操作步数模仿手工除法,而是利用减法操作实现的。
其基本思想是反复做除法,看从被除数里面最多能减去多少个除数,商就是多少。
逐个减显然太慢,要判断一次最多能减少多少个整的10的n次方。
以7546除23为例。
先减去23的100倍,就是2300,可以减3次,余下646。此时商就是300;
然后646减去23的10倍,就是230,可以减2次,余下186。此时商就是320;
然后186减去23,可以减8次,此时商就是328。
从这里不难看出,所谓补“0”只不过是减得快一点罢了,其本质依旧是高精度乘法的逆运算。
(不过我自己实现的时候由于memset和数组传递的原因,在数组迭代更新的地方有点乱,稍微改一改就好了,思路是这样。用vector因该比较方便。)
看到过二分找商,用乘法来验算,很简单了。
板子
压8位(基本输入输出 关系比较 加减法 高精度乘法 高精度除以低精)
#include <bits/stdc++.h>using namespace std;typedef long long ll;struct BigInteger{friend BigInteger operator+(const BigInteger &lhs,const BigInteger &rhs);static const int BASE = 100000000;static const int WIDTH = 8;vector<ll> s;BigInteger(ll num = 0){*this = num;}BigInteger operator = (ll num){s.clear();do{s.push_back(num % BASE);num /= BASE;}while(num > 0);return *this;}// 从右往左压位存BigInteger operator = (const string& str){s.clear();int x,len = (str.length() - 1) / WIDTH + 1;// 注意数组从0开始数for(int i = 0;i < len;i ++){// 从后截取一段长度为WIDTH的字符int end = str.length() - i * WIDTH;int start = max(0, end - WIDTH);sscanf(str.substr(start, end-start).c_str(),"%d",&x);s.push_back(x);}return *this;}BigInteger operator += (const BigInteger& rhs){*this = *this + rhs;return *this;}};BigInteger operator+(const BigInteger &lhs,const BigInteger &rhs){BigInteger sum;sum.s.clear();// 重要 重置初始化for(int i = 0,g = 0;;i ++)// g是上次加法所进位{if(g == 0 && i >= lhs.s.size() && i >= rhs.s.size()) break;ll x = g;if(i < lhs.s.size()) x += lhs.s[i];if(i < rhs.s.size()) x += rhs.s[i];sum.s.push_back(x % BigInteger::BASE);g = x / BigInteger::BASE;}return sum;}bool operator<(const BigInteger &lhs,const BigInteger &rhs){if(lhs.s.size() != rhs.s.size()) return lhs.s.size() < rhs.s.size();for(int i = lhs.s.size() - 1;i >= 0;i --)if(lhs.s[i] != rhs.s[i]) return lhs.s[i] < rhs.s[i];return 0;// 相等0}// 返回两数相减的绝对值BigInteger operator-(const BigInteger &lhs,const BigInteger &rhs){BigInteger l = lhs,r = rhs;BigInteger dif;dif.s.clear();// 重要 重置初始化if(l < r)swap(l,r);// 保证左值最大for(int i = 0;i < l.s.size();i ++){ll x = l.s[i];if(i < r.s.size())x -= r.s[i];// 注意越界if(x < 0)// 借位{x += BigInteger::BASE;l.s[i + 1] --;}dif.s.push_back(x);}return dif;}bool operator>(const BigInteger &lhs,const BigInteger &rhs){return rhs < lhs;}bool operator<=(const BigInteger &lhs,const BigInteger &rhs){return !(rhs < lhs);}bool operator>=(const BigInteger &lhs,const BigInteger &rhs){return !(lhs < rhs);}bool operator==(const BigInteger &lhs, const BigInteger &rhs){return !(lhs < rhs) && !(rhs < lhs);}bool operator!=(const BigInteger &lhs,const BigInteger &rhs){return !(lhs == rhs);}ostream &operator<<(ostream &os, const BigInteger &x){os << x.s.back();// 首位可能长度不足WIDTHfor(int i = x.s.size() - 2;i >= 0;i --){char buf[20];sprintf(buf, "%08d" ,x.s[i]);// x.s[i]可能为ll(00012345) 补前面的0for(int j = 0;j < strlen(buf); j++) os << buf[j];}return os;}istream &operator>>(istream &is, BigInteger &x){string s;if(!(is >> s)) return is;x = s;return is;}int main(){string a,b;cin >> a >> b;BigInteger x,y;x = a;y = b;if(a == b) cout << 0;else{if(x < y) cout << "-";cout << operator-(x,y);}return 0;}
压1位(所有四则运算和取余)
高精度四则运算
#include <bits/stdc++.h>#define MAXN 60000using namespace std;typedef long long ll;void value(string x,ll (&a)[MAXN]){memset(a,0,sizeof(a));a[0] = x.size();for(int i = 1;i <= a[0];i ++)a[i] = x[a[0] - i] - '0';}void print(const ll (&a)[MAXN]){bool ok = 0;for(int i = a[0];i >= 1;i --){if(a[i] != 0) ok = 1;if(ok) putchar(a[i] + '0');}if(!ok) putchar('0');putchar('\n');}void add(const ll (&a)[MAXN],const ll (&b)[MAXN],ll (&c)[MAXN]){memset(c,0,sizeof(c));for(int i = 1,g = 0;;i ++){if(g == 0 && i > a[0] && i > b[0]) break;c[i] = (g + a[i] + b[i]) % 10;g = (g + a[i] + b[i]) / 10;}c[0] = max(a[0],b[0]);if(c[c[0] + 1]) c[0] ++;}void multi(const ll (&a)[MAXN],const ll(&b)[MAXN], ll(&c)[MAXN]){memset(c,0,sizeof(c));for(int i = 1;i <= b[0];i++){for(int j = 1;j <= a[0]; j++){int k = i + j - 1;c[k] += b[i] * a[j];}}c[0] = a[0] + b[0];for(int i = 1;i <= c[0];i ++)if(c[i] > 9){c[i + 1] += c[i] / 10;c[i] %= 10;}while(c[c[0]] == 0 && c[0] > 1)// 保证有1位(0)c[0]--;}bool bigger(ll (&a)[MAXN], ll (&b)[MAXN]){if(a[0] != b[0]) return a[0] > b[0];for(int i = a[0];i >= 1;i --)if(a[i] != b[i]) return a[i] > b[i];return 0;// 相等}bool minu(ll (&a)[MAXN], ll(&b)[MAXN], ll(&c)[MAXN])// c=a-b绝对值 返回是否为负数{bool big = bigger(b,a);memset(c,0,sizeof(c));if(big) swap(a,b);for(int i = 1;i <= a[0];i ++){c[i] += a[i] - b[i];if(c[i] < 0){c[i] += 10;c[i + 1]--;}}c[0] = max(a[0], b[0]);while(c[c[0]] == 0 && c[0] > 1) c[0]--;return big;}// 方便memset和传递void div(ll (&a)[MAXN], ll(&b)[MAXN], ll(&c)[MAXN], ll(&moveb)[MAXN], ll(&temp)[MAXN]){memset(c,0,sizeof(c));// 处理两种特殊情况: 相等和小于if(bigger(b,a)){c[0] = 1;c[1] = 0;return;}if(!bigger(a,b) && !bigger(b,a)){c[0] = 1;c[1] = 1;return;}ll t = a[0] - b[0];c[0] = max(a[0],b[0]);while(t >= 0){memset(moveb,0,sizeof(moveb));// 移动moveb[0] = t + b[0];for(int i = 1;i <= b[0];i ++)moveb[t + i] = b[i];for(int i = 0;i <= a[0];i ++) temp[i] = a[i];while(bigger(temp,moveb)){minu(a,moveb,temp);c[t + 1] ++;for(int i = 0;i <= temp[0];i ++) a[i] = temp[i];}t --;}while(c[c[0]] == 0 && c[0] > 1) c[0]--;}void mod(ll (&a)[MAXN], ll(&b)[MAXN], ll(&c)[MAXN], ll(&moveb)[MAXN]){memset(c,0,sizeof(c));// 处理两种特殊情况: 相等和小于if(bigger(b,a)){for(int i = 0;i <= a[0];i ++) c[i] = a[i];return;}if(!bigger(a,b) && !bigger(b,a)){c[0] = 0;c[1] = 0;return;}ll t = a[0] - b[0];c[0] = max(a[0],b[0]);while(t >= 0){memset(moveb,0,sizeof(moveb));// 移动moveb[0] = t + b[0];for(int i = 1;i <= b[0];i ++)moveb[t + i] = b[i];for(int i = 0;i <= a[0];i ++) c[i] = a[i];while(bigger(c,moveb)){minu(a,moveb,c);for(int i = 0;i <= c[0];i ++) a[i] = c[i];}t --;}while(c[c[0]] == 0 && c[0] > 1) c[0]--;}ll a[MAXN],b[MAXN],c[MAXN], moveb[MAXN],temp[MAXN];int main(){string x,y;cin >> x >> y;value(x,a);value(y,b);add(a,b,c);print(c);value(x,a);value(y,b);if(minu(a,b,c)) putchar('-');print(c);value(x,a);value(y,b);multi(a,b,c);print(c);value(x,a);value(y,b);div(a,b,c,moveb,temp);print(c);value(x,a);value(y,b);mod(a,b,c,moveb);print(c);return 0;}
高精度除以低精度
#include <bits/stdc++.h>using namespace std;int main(){string a;long long b,d = 0;vector<int> ans;cin >> a >> b;// 从左往右存for(int i = 0;i < a.length();i ++){int t = a[i] - '0';ans.push_back((d * 10 + t) / b);d = (d * 10 + t) % b;}bool ok = false;for(int i = 0;i < ans.size();i ++){if(ans[i] != 0) ok = true;// 前导零if(ok) cout << ans[i];}return 0;}
