1. 程式人生 > 其它 >第一章 高精度(一)

第一章 高精度(一)

自我介紹大家好,我是小魚,目前是一名本科大二的學生,這是我的第一篇,在接下來的日子裡,我將會分類講解各種不同的資料結構與演算法,希望可以與大家共同進步,共同成長。

本章介紹:眾所周知,在處理數與數的運算時,一旦兩個數的位數超過了所使用的資料型別時,便會出現溢位(對於數的溢位,我們在後續的文章中會詳細講解)。為了應對這種情況,高精度演算法應運而生。高精度演算法是用於計算機對於超大資料的一種模擬加、減、乘、除、乘方、階乘等運算。(本章的程式碼已通過洛谷和ACWing的全部測試點)

4種資料型別及取值範圍:

byte:-2^7~2^7-1 ,即 -128~127, 1位元組

short:-2^15~2^15-1 ,即-32768~32767 , 2位元組

有符號 int : -2^31~2^31-1 ,即-2147483648~2147483647, 4位元組

無符號 int : 0~2^32-1

long : -2^63~2^63-1 ,即-9223372036854774808~9223372036854774807, 8位元組

高精度加法

題目描述:

給定兩個正整數a,b,計算它們的和。

輸入格式:

共兩行,每行包含一個整數。

輸出格式:

輸出只有一行,代表a+b的值

資料範圍:

a,b10500

題目分析:

本題目是最基礎的高精度題型,對於這類問題,我通常採用字串處理。

核心點:與小學時做加法的步驟相似,一位一位的對著加,注意儲存進位。

本題另一個核心點就是明白數字和字串的區別在哪裡,即個位數字在哪裡

1.使用數字儲存時,個位是字串的最後一位;

2.兩個字串相加,因為字串的長度可能不一致,所以最好翻轉過來,這樣字串就變成了個位在前;

3.相加的過程即,定義一個s=0,用s分別與每個字串的第i,j位相加,十位做下一次迴圈;

 1 #include
 2 #include
 3 #include
 4 using namespace std;
 5 const int N=100010;
 6 string A,B;
 7 string add(const string &A,const string &B){
 8     string C;//C=A+B;
 9     int s=0;
10     for(int i=A.size()-1,j=B.size()-1;i>=0||j>=0||s>0;i--,j--){
11         if(i>=0) s+=(A[i]-'0');
12         if(j>=0) s+=(B[j]-'0');
13         C+=((s%10)+'0');//用C來儲存相加的結果
14         s=s/10;//去除掉s的個位,把s的十位放到下一次的迴圈中
15     }
16     reverse(C.begin(),C.end());
17     return C;
18 }
19 int main(){
20     cin>>A>>B;
21     cout<<add(A,B)<<endl;
22     return 0;
23 }

附上高精度加法的程式碼模板

 1 string add(const string &A,const string &B){
 2     string C;//C=A+B;
 3     int s=0;
 4     for(int i=A.size()-1,j=B.size()-1;i>=0||j>=0||s>0;i--,j--){
 5         if(i>=0) s+=(A[i]-'0');
 6         if(j>=0) s+=(B[j]-'0');
 7         C+=((s%10)+'0');
 8         s=s/10;
 9     }
10     reverse(C.begin(),C.end());
11     return C;
12 }

高精度減法

題目描述:

給定兩個正整數a,b,計算它們的差。

輸入格式:

共兩行,每行包含一個整數。

輸出格式:

輸出只有一行,代表a+b的值。

資料範圍:

a,b10500

題目分析:

高精度減法的思想與高精度加法類似,可以用同一種思路寫。但對減完之後0的字尾問題和字典序大小的比較仍需要討論

核心思想:

1.同上面高精度加法,但對於類似30-30的問題,計算結果可能會出現00的情況,或輸入003、10得到結果應為-8.面對這種情況,我們應該才用去0操作,分別在處理資料前,做去0操作,在計算後,對計算結果,做去0操作;

2.減法需要比較字典序的大小,字典序較大的應作為被減的一方,以防止出現倒序後高位不夠減的情況;

 1 #include 
 2 #include 
 3 using namespace std;
 4 const int N = 1000010;
 5 
 6 bool cmp(vector &A, vector &B)//比較A,B的字典序,用字典序大的減小的 
 7 {
 8     if (A.size() != B.size()) return A.size() >= B.size();
 9     for (int i = A.size() - 1; i >= 0; i--) 
10         if (A[i] != B[i])
11             return A[i] > B[i];
12     return true;
13 }
14 
15 void trimZero(vector &A)//去0操作 
16 {
17     while (A.back() == 0 && A.size() > 1) A.pop_back();//若A的最後一位是0且A至少有一位,去除A的0字尾 
18 }
19 
20 vector sub(vector &A, vector &B)
21 {
22     vector C;
23     int t = 0;
24     for (int i = 0; i < A.size(); i++)
25     {
26         t = A[i] - t;
27         if (i < B.size()) t -= B[i];
28         C.push_back((t + 10) % 10);
29         if (t < 0) t = 1;//t<0說明t向前借了一位 
30         else t = 0;//否則把t置為0,進行下一位的運算 
31     }
32     trimZero(C);
33     return C;
34 }
35 
36 int main()
37 {
38     string a, b;
39     cin >> a >> b;
40     vector A, B, C;
41     for (int i = a.size() - 1; i >= 0; i--) A.push_back(a[i] - '0');//把字串轉為數字 
42     for (int i = b.size() - 1; i >= 0; i--) B.push_back(b[i] - '0');
43 
44     trimZero(A), trimZero(B);//去後綴0 
45 
46     if (cmp(A, B)) C = sub(A, B);
47     else {
48         C = sub(B, A);
49         printf("-");
50     }
51     for (int i = C.size() - 1; i >= 0; i--) cout << C[i];
52     return 0;
53 }

附上高精度減法的程式碼模板

 1 bool cmp(vector &A, vector &B)//比較A,B的字典序,用字典序大的減小的 
 2 {
 3     if (A.size() != B.size()) return A.size() >= B.size();
 4     for (int i = A.size() - 1; i >= 0; i--) 
 5         if (A[i] != B[i])
 6             return A[i] > B[i];
 7     return true;
 8 }
 9 
10 void trimZero(vector &A)//去0操作 
11 {
12     while (A.back() == 0 && A.size() > 1) A.pop_back();//若A的最後一位是0且A至少有一位,去除A的0字尾 
13 }
14 
15 vector sub(vector &A, vector &B)//做A-B操作 
16 {
17     vector C;
18     int t = 0;
19     for (int i = 0; i < A.size(); i++)
20     {
21         t = A[i] - t;
22         if (i < B.size()) t -= B[i];
23         C.push_back((t + 10) % 10);
24         if (t < 0) t = 1;//t<0說明t向前借了一位 
25         else t = 0;//否則把t置為0,進行下一位的運算 
26     }
27     trimZero(C);
28     return C;
29 }

總結

這篇文章講解了高精度加法和高精度減法的求解方法關鍵點如下:

高精度加法

1.記住字串中個位在後面,高位在前面,要把字串翻轉一下;

2.定義一個s=0,用s分別與每個字串的第i,j位相加,十位做下一次迴圈;

高精度加法

1.字尾為0的情況要去0;

2.比較字典序的大小,字典序大的作為減數;

接下來的文章將為大家介紹高精度乘法和高精度除法,難度會有所提升,大家敬請期待。