高精度

用高精度处理很长很长的数字。

基本思想是压位, 压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位(基本输入输出 关系比较 加减法 高精度乘法 高精度除以低精)

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. typedef long long ll;
  4. struct BigInteger
  5. {
  6. friend BigInteger operator+(const BigInteger &lhs,const BigInteger &rhs);
  7. static const int BASE = 100000000;
  8. static const int WIDTH = 8;
  9. vector<ll> s;
  10. BigInteger(ll num = 0){*this = num;}
  11. BigInteger operator = (ll num)
  12. {
  13. s.clear();
  14. do
  15. {
  16. s.push_back(num % BASE);
  17. num /= BASE;
  18. }while(num > 0);
  19. return *this;
  20. }
  21. // 从右往左压位存
  22. BigInteger operator = (const string& str)
  23. {
  24. s.clear();
  25. int x,len = (str.length() - 1) / WIDTH + 1;// 注意数组从0开始数
  26. for(int i = 0;i < len;i ++)
  27. {
  28. // 从后截取一段长度为WIDTH的字符
  29. int end = str.length() - i * WIDTH;
  30. int start = max(0, end - WIDTH);
  31. sscanf(str.substr(start, end-start).c_str(),"%d",&x);
  32. s.push_back(x);
  33. }
  34. return *this;
  35. }
  36. BigInteger operator += (const BigInteger& rhs)
  37. {
  38. *this = *this + rhs;
  39. return *this;
  40. }
  41. };
  42. BigInteger operator+(const BigInteger &lhs,const BigInteger &rhs)
  43. {
  44. BigInteger sum;
  45. sum.s.clear();// 重要 重置初始化
  46. for(int i = 0,g = 0;;i ++)// g是上次加法所进位
  47. {
  48. if(g == 0 && i >= lhs.s.size() && i >= rhs.s.size()) break;
  49. ll x = g;
  50. if(i < lhs.s.size()) x += lhs.s[i];
  51. if(i < rhs.s.size()) x += rhs.s[i];
  52. sum.s.push_back(x % BigInteger::BASE);
  53. g = x / BigInteger::BASE;
  54. }
  55. return sum;
  56. }
  57. bool operator<(const BigInteger &lhs,const BigInteger &rhs)
  58. {
  59. if(lhs.s.size() != rhs.s.size()) return lhs.s.size() < rhs.s.size();
  60. for(int i = lhs.s.size() - 1;i >= 0;i --)
  61. if(lhs.s[i] != rhs.s[i]) return lhs.s[i] < rhs.s[i];
  62. return 0;// 相等0
  63. }
  64. // 返回两数相减的绝对值
  65. BigInteger operator-(const BigInteger &lhs,const BigInteger &rhs)
  66. {
  67. BigInteger l = lhs,r = rhs;
  68. BigInteger dif;
  69. dif.s.clear();// 重要 重置初始化
  70. if(l < r)
  71. swap(l,r);// 保证左值最大
  72. for(int i = 0;i < l.s.size();i ++)
  73. {
  74. ll x = l.s[i];
  75. if(i < r.s.size())
  76. x -= r.s[i];// 注意越界
  77. if(x < 0)// 借位
  78. {
  79. x += BigInteger::BASE;
  80. l.s[i + 1] --;
  81. }
  82. dif.s.push_back(x);
  83. }
  84. return dif;
  85. }
  86. bool operator>(const BigInteger &lhs,const BigInteger &rhs)
  87. {
  88. return rhs < lhs;
  89. }
  90. bool operator<=(const BigInteger &lhs,const BigInteger &rhs)
  91. {
  92. return !(rhs < lhs);
  93. }
  94. bool operator>=(const BigInteger &lhs,const BigInteger &rhs)
  95. {
  96. return !(lhs < rhs);
  97. }
  98. bool operator==(const BigInteger &lhs, const BigInteger &rhs)
  99. {
  100. return !(lhs < rhs) && !(rhs < lhs);
  101. }
  102. bool operator!=(const BigInteger &lhs,const BigInteger &rhs)
  103. {
  104. return !(lhs == rhs);
  105. }
  106. ostream &operator<<(ostream &os, const BigInteger &x)
  107. {
  108. os << x.s.back();// 首位可能长度不足WIDTH
  109. for(int i = x.s.size() - 2;i >= 0;i --)
  110. {
  111. char buf[20];
  112. sprintf(buf, "%08d" ,x.s[i]);// x.s[i]可能为ll(00012345) 补前面的0
  113. for(int j = 0;j < strlen(buf); j++) os << buf[j];
  114. }
  115. return os;
  116. }
  117. istream &operator>>(istream &is, BigInteger &x)
  118. {
  119. string s;
  120. if(!(is >> s)) return is;
  121. x = s;
  122. return is;
  123. }
  124. int main()
  125. {
  126. string a,b;cin >> a >> b;
  127. BigInteger x,y;
  128. x = a;
  129. y = b;
  130. if(a == b) cout << 0;
  131. else{
  132. if(x < y) cout << "-";
  133. cout << operator-(x,y);
  134. }
  135. return 0;
  136. }

压1位(所有四则运算和取余)

高精度四则运算

  1. #include <bits/stdc++.h>
  2. #define MAXN 60000
  3. using namespace std;
  4. typedef long long ll;
  5. void value(string x,ll (&a)[MAXN])
  6. {
  7. memset(a,0,sizeof(a));
  8. a[0] = x.size();
  9. for(int i = 1;i <= a[0];i ++)
  10. a[i] = x[a[0] - i] - '0';
  11. }
  12. void print(const ll (&a)[MAXN])
  13. {
  14. bool ok = 0;
  15. for(int i = a[0];i >= 1;i --)
  16. {
  17. if(a[i] != 0) ok = 1;
  18. if(ok) putchar(a[i] + '0');
  19. }
  20. if(!ok) putchar('0');
  21. putchar('\n');
  22. }
  23. void add(const ll (&a)[MAXN],const ll (&b)[MAXN],ll (&c)[MAXN])
  24. {
  25. memset(c,0,sizeof(c));
  26. for(int i = 1,g = 0;;i ++)
  27. {
  28. if(g == 0 && i > a[0] && i > b[0]) break;
  29. c[i] = (g + a[i] + b[i]) % 10;
  30. g = (g + a[i] + b[i]) / 10;
  31. }
  32. c[0] = max(a[0],b[0]);
  33. if(c[c[0] + 1]) c[0] ++;
  34. }
  35. void multi(const ll (&a)[MAXN],const ll(&b)[MAXN], ll(&c)[MAXN])
  36. {
  37. memset(c,0,sizeof(c));
  38. for(int i = 1;i <= b[0];i++)
  39. {
  40. for(int j = 1;j <= a[0]; j++)
  41. {
  42. int k = i + j - 1;
  43. c[k] += b[i] * a[j];
  44. }
  45. }
  46. c[0] = a[0] + b[0];
  47. for(int i = 1;i <= c[0];i ++)
  48. if(c[i] > 9)
  49. {
  50. c[i + 1] += c[i] / 10;
  51. c[i] %= 10;
  52. }
  53. while(c[c[0]] == 0 && c[0] > 1)// 保证有1位(0)
  54. c[0]--;
  55. }
  56. bool bigger(ll (&a)[MAXN], ll (&b)[MAXN])
  57. {
  58. if(a[0] != b[0]) return a[0] > b[0];
  59. for(int i = a[0];i >= 1;i --)
  60. if(a[i] != b[i]) return a[i] > b[i];
  61. return 0;// 相等
  62. }
  63. bool minu(ll (&a)[MAXN], ll(&b)[MAXN], ll(&c)[MAXN])// c=a-b绝对值 返回是否为负数
  64. {
  65. bool big = bigger(b,a);
  66. memset(c,0,sizeof(c));
  67. if(big) swap(a,b);
  68. for(int i = 1;i <= a[0];i ++)
  69. {
  70. c[i] += a[i] - b[i];
  71. if(c[i] < 0)
  72. {
  73. c[i] += 10;
  74. c[i + 1]--;
  75. }
  76. }
  77. c[0] = max(a[0], b[0]);
  78. while(c[c[0]] == 0 && c[0] > 1) c[0]--;
  79. return big;
  80. }
  81. // 方便memset和传递
  82. void div(ll (&a)[MAXN], ll(&b)[MAXN], ll(&c)[MAXN], ll(&moveb)[MAXN], ll(&temp)[MAXN])
  83. {
  84. memset(c,0,sizeof(c));
  85. // 处理两种特殊情况: 相等和小于
  86. if(bigger(b,a))
  87. {
  88. c[0] = 1;
  89. c[1] = 0;
  90. return;
  91. }
  92. if(!bigger(a,b) && !bigger(b,a))
  93. {
  94. c[0] = 1;
  95. c[1] = 1;
  96. return;
  97. }
  98. ll t = a[0] - b[0];
  99. c[0] = max(a[0],b[0]);
  100. while(t >= 0)
  101. {
  102. memset(moveb,0,sizeof(moveb));
  103. // 移动
  104. moveb[0] = t + b[0];
  105. for(int i = 1;i <= b[0];i ++)
  106. moveb[t + i] = b[i];
  107. for(int i = 0;i <= a[0];i ++) temp[i] = a[i];
  108. while(bigger(temp,moveb))
  109. {
  110. minu(a,moveb,temp);
  111. c[t + 1] ++;
  112. for(int i = 0;i <= temp[0];i ++) a[i] = temp[i];
  113. }
  114. t --;
  115. }
  116. while(c[c[0]] == 0 && c[0] > 1) c[0]--;
  117. }
  118. void mod(ll (&a)[MAXN], ll(&b)[MAXN], ll(&c)[MAXN], ll(&moveb)[MAXN])
  119. {
  120. memset(c,0,sizeof(c));
  121. // 处理两种特殊情况: 相等和小于
  122. if(bigger(b,a))
  123. {
  124. for(int i = 0;i <= a[0];i ++) c[i] = a[i];
  125. return;
  126. }
  127. if(!bigger(a,b) && !bigger(b,a))
  128. {
  129. c[0] = 0;
  130. c[1] = 0;
  131. return;
  132. }
  133. ll t = a[0] - b[0];
  134. c[0] = max(a[0],b[0]);
  135. while(t >= 0)
  136. {
  137. memset(moveb,0,sizeof(moveb));
  138. // 移动
  139. moveb[0] = t + b[0];
  140. for(int i = 1;i <= b[0];i ++)
  141. moveb[t + i] = b[i];
  142. for(int i = 0;i <= a[0];i ++) c[i] = a[i];
  143. while(bigger(c,moveb))
  144. {
  145. minu(a,moveb,c);
  146. for(int i = 0;i <= c[0];i ++) a[i] = c[i];
  147. }
  148. t --;
  149. }
  150. while(c[c[0]] == 0 && c[0] > 1) c[0]--;
  151. }
  152. ll a[MAXN],b[MAXN],c[MAXN], moveb[MAXN],temp[MAXN];
  153. int main()
  154. {
  155. string x,y;cin >> x >> y;
  156. value(x,a);
  157. value(y,b);
  158. add(a,b,c);
  159. print(c);
  160. value(x,a);
  161. value(y,b);
  162. if(minu(a,b,c)) putchar('-');
  163. print(c);
  164. value(x,a);
  165. value(y,b);
  166. multi(a,b,c);
  167. print(c);
  168. value(x,a);
  169. value(y,b);
  170. div(a,b,c,moveb,temp);
  171. print(c);
  172. value(x,a);
  173. value(y,b);
  174. mod(a,b,c,moveb);
  175. print(c);
  176. return 0;
  177. }

高精度除以低精度

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. int main()
  4. {
  5. string a;long long b,d = 0;vector<int> ans;
  6. cin >> a >> b;
  7. // 从左往右存
  8. for(int i = 0;i < a.length();i ++)
  9. {
  10. int t = a[i] - '0';
  11. ans.push_back((d * 10 + t) / b);
  12. d = (d * 10 + t) % b;
  13. }
  14. bool ok = false;
  15. for(int i = 0;i < ans.size();i ++)
  16. {
  17. if(ans[i] != 0) ok = true;// 前导零
  18. if(ok) cout << ans[i];
  19. }
  20. return 0;
  21. }