算法学习之高精度

  我们知道C++最大的整数类型为unsigned long long,而unsigned long long最高只能存储64位整数,当我们遇到了几百位的整数进行运算时,我们不能直接使用c++的数据类型来存储这些整数,这时候就需要一个名为高精度的算法来帮忙运算。

  首先我们需要知道,在我们小学的时候就学过列式运算,无论是加减乘除都可以用这个办法。因此,高精度也是通过模拟烈士运算来实现的。

  我们以洛谷P1009这道题为例子,来学习高精度是如何实现的。

  题目:用高精度计算出 S=1!+2!+3!+⋯+n!,其中n<=50。

  观察题目,我们发现这题应该需要两个高精度,分别是加法和乘法。当我们的n>21后,计算出来的n!就会超出unsigned long long的范围,所以我们需要高精度乘法,又是求前n项阶乘之和,则需要使用高精度加法。

  所以我们可以模拟一下列式计算,来帮助我们更好的理解高精度加法

  我们使用两个数组分别存储大数A和大数B,个位放在数组的第一位。使用整数t来存储每次高位的进位数的大小,t的初始值为0。

  例如:123 + 29

  A[0] = 3, B[0] = 9,t = A[0] + B[0] = 12

  因为t>10,所以我们要向高位进1,并将t对10取余,这时候个位就是2

  同理,这时候t = A[1]+B[1]+t = 5,加t是因为进1了,这时候t<10,不需要进1,百位就直接是t。

  最后得到答案为152。

  下面是高精度加法的代码模板,源于Acwing。

 1 vector<int> add(vector<int> &A,vector<int> &B){
 2     vector<int>C;
 3     
 4     int t = 0;//进位
 5     
 6     for(int i=0;i<A.size()||i<B.size();i++){
 7         if(i<A.size()) t+=A[i];
 8         if(i<B.size()) t+=B[i];
 9         C.push_back(t%10);
10         t/=10;
11     }
12     if(t) C.push_back(1);//t>0,进位
13     return C;
14 }

  跟高精度加法一样,高精度乘法本质也是模拟列式运算。但是和普通的列式运算不同,我们需要用大数A的每一位数字和整数b相乘,

  下面是高精度乘法的代码模板,源于AcWing。

 1 vector<int> mul(vector<int> &A,int b){
 2     vector<int>C;
 3     
 4     int t = 0;//进位
 5     
 6     for(int i=0;i<A.size()||t;i++){
 7         if(i<A.size())t = t + A[i] * b;
 8         C.push_back(t%10);
 9         t/=10; 
10     }
11     while(C.size()>1&&C.back()==0) C.pop_back();//去除前导0
12     return C;
13 }

  当我们学会了这两种算法之后,上面的那道题就很好解决了。

  首先求每一个数的阶乘,然后再把它们相加后输出即可。

  以下是我的AC代码,仅供参考。

 1 #include <iostream>
 2 #include <vector>
 3 
 4 using namespace std;
 5 typedef long long ll;
 6 
 7 vector<int> mul(vector<int> &A,int b){
 8     vector<int>C;
 9     
10     int t = 0;
11     
12     for(int i=0;i<A.size()||t;i++){
13         if(i<A.size())t = t + A[i] * b;
14         C.push_back(t%10);
15         t/=10; 
16     }
17     while(C.size()>1&&C.back()==0) C.pop_back();
18     return C;
19 }
20 
21 vector<int> add(vector<int> &A,vector<int> &B){
22     vector<int>C;
23     
24     int t = 0;
25     
26     for(int i=0;i<A.size()||i<B.size();i++){
27         if(i<A.size()) t+=A[i];
28         if(i<B.size()) t+=B[i];
29         C.push_back(t%10);
30         t/=10;
31     }
32     if(t) C.push_back(1);
33     return C;
34 }
35 
36 int main(){
37     int n;
38     cin>>n;
39     vector<int>A,B;
40     A.push_back(1);
41     B.push_back(1);
42     for(int i=2;i<=n;i++){
43             A = mul(A,i);
44             B = add(B,A);
45     }
46     for(int i=B.size()-1;i>=0;i--){
47         cout<<B[i];
48     }
49     return 0;
50 }

  感谢您的阅读,愿您算法之旅一路顺风。


 

    

  

 

posted @ 2023-10-30 16:10  Linglo  阅读(29)  评论(0)    收藏  举报