更改
2021.2.6
更改了文末統計字數的方式
1 高精度算法
正經的定義是:
高精度算法(High Accuracy Algorithm)是處理大數字的數學計算方法。在一般的科學計算中,會經常算到小數點后幾百位或者更多,當然也可能是幾千億幾百億的大數字。一般這類數字我們統稱為高精 度數,高精度算法是用計算機對於超大數據的一種模擬加,減,乘,除,乘方,階乘,開方等運算。對於非常龐大的數字無法在計算機中正常存儲,於是,將這個數字拆開,拆成一位一位的,或者是四位四位的存儲到一個數組中, 用一個數組去表示一個數字,這樣這個數字就被稱為是高精度數。高精度算法就是能處理高精度數各種運算的算法,但又因其特殊性,故從普通數的算法中分離,自成一家。
但是,作為一個剛入門的,我個人的理解就是:
用數組以按照數位拆分一個大於double/long long等范圍的數據,然后進行處理。
至於好處,我認為,就是對於超大(高精度)數據的使用
(當然肯定比處理一般的數據麻煩一點,要不然單列出來學干嘛)
2 高精度加法
①算法分析
上來一看,這個數據被拆分成了一個個位,作為計算能力非常之差的憨批,我很容易就想到了早在小學就學習過的最基礎的加法計算方法:列 豎 式
(圖源度娘 相信大家都對這陌生了,但是我兩位數加兩位數天天用)
這個的基礎就是兩個數對應的每個數位相加,但是這樣就涉及一個問題:進 位
不過這個還是挺簡單的,兩個一位數相加最多也就進1,於是我們馬上就可以愉快地開始用代碼實現了。
②代碼實現
首先是理一下思路:
- 錄入數據:用字符串/字符數組接收,再逆序存到int/float/double數組,以便於計算
(這個地方倒序的原因是如果牽扯到進位,正序的話進位,下標要-1,要是第一個進位的話......那數組會非常的開心,我也是。於是用倒序,進位的時候下標+1,只要數組開的夠長就好了,最后逆序輸出就好了) - 進行加法運算:根據剛才算法分析中的用while循環完成就可以了(
雖然我個人比較喜歡用for,但是那樣有麻煩了億點) - 輸出數據:因為是逆序輸入,所以逆序輸出。
以下是代碼
害怕自己以后看不懂所以加了很多很Dai的注釋
//高精度加法
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
int a[201],b[201],c[201];//三個int數組來儲存數據進行運算
int main()
{
char na[201],nb[201];
//兩個用來接收數據的字符串(字符數組)
gets(na);
gets(nb);
//接收數據
int la=strlen(na);
int lb=strlen(nb);
//計算長度
for(int i=0;i<la;i++){
a[la-i]=na[i]-'0';
}
for(int i=0;i<lb;i++){
b[lb-i]=nb[i]-'0';
}
//將數據倒序存入
int lc=1,x=0;
//這里的x是進位的數 ,初始為0
while(lc<=la||lc<=lb){//這里算到不包括最后一次進位的最高位
c[lc]=a[lc]+b[lc]+x;//這里是a+b+進位數
x=c[lc]/10;//讓進位數等於結果的十位
c[lc]%=10;//讓此位結果變為初步結果的個位
lc++;//要計算的位數+1
}
//加法計算的核心,這里算到不包括最后一次進位的最高位
c[lc]=x;
//如果最后一次計算有進位數,讓進位數等於新高位
if(c[lc]==0)
lc--;
//如果沒有進位,那么把lc--以便輸出
for(int i=lc;i>0;i--)
cout<<c[i];
cout<<endl;
//輸出,收尾(
return 0;
}
學的時候沒覺出來,自己敲的時候發現還是得注意一些小細節的,比如要判斷最后的lc這一位是否等於0
(當然應該是我太菜了才會把這些東西當成細節)
3 高精度減法
①算法分析
和加法一樣,用列 豎 式的方法,這里只需要考慮不 夠 減 要 借 位的問題。
(圖源某小學課件 又是大家非常陌生而我每次兩位數減一位數的時候都要用的東西)
那么具體的解決方法就是不夠減的時候本位+10,上一位-1,非常簡單
②代碼實現
還是理一下思路:
- 錄入數據:用字符串/字符數組接收,再逆序存到int/float/double數組,以便於計算
- 進行減法運算:
- 判斷被減數是否小於減數,如果是的話交換順序並先輸出一個負號
- while+判斷完成算法分析中分析到的借位問題
- 輸出數據:因為是逆序輸入,所以逆序輸出。
(應該沒有人發現我是復制的)
以下是代碼
很Dai的注釋更多了,各位看着笑笑就好
//高精度減法
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int a1[256]={0},a2[256]={0},a[256]={0};
//聲明來存數的數組
int main()
{
char n1[256],n2[256],m[256];//用於接收數據的字符串(字符數組),以及m這個后面用來交換用的中間量
gets(n1);
gets(n2);
//接收數據,這里默認是n1-n2
if((strlen(n1)<strlen(n2))||(strlen(n1)==strlen(n2)&&strcmp(n1,n2)<0))
//判斷被減數是否小於減數
//第一個判斷條件很好懂,是被減數的位數少於減數
//第二個是當兩者位數相同時,使用strcmp進行比較
/*strcmp:
strcmp(n1,n2)就是從n1[0]和n2[0]開始比較(以ASCⅡ里的順序來比較)
若前者大,則返回大於0的數
反之,返回小於0的數
若相同,則返回0
(這樣理解,可能不准確,於是去問了下度娘:)
strcmp函數是string compare(字符串比較)的縮寫,
用於比較兩個字符串並根據比較結果返回整數。
基本形式為strcmp(str1,str2),若str1=str2,則返回零;
str1<str2,則返回負數;若str1>str2,則返回正數。
(嘛,還是差不多的)
*/
{
strcpy(m,n1);
strcpy(n1,n2);
strcpy(n2,m);
/*
strcpy就是用后者賦值給前者,復制貼貼
怕自己這個蒟蒻看不懂於是又去了一趟度娘(蒟蒻的日常)
strcpy,即string copy(字符串復制)的縮寫。
strcpy是C++語言的一個標准函數 ,
strcpy把含有'\0'結束符的字符串復制到另一個地址空間,
返回值的類型為char*。
*/
cout<<"-";//先輸出一個負號,這樣后面就可以安心的運算了(蒟蒻發言)
}
int l1=strlen(n1),l2=strlen(n2);
for(int i=0;i<l1;i++)
a1[l1-i]=int(n1[i]-'0');
for(int i=0;i<l2;i++)
a2[l2-i]=int(n2[i]-'0');
//將數據存入int類型數組,不用多說
int x=1;
//x代表要計算的是第幾位數
while(x<=l1||x<=l2)
{
if(a1[x]<a2[x])
{
a1[x]+=10;
a1[x+1]--;
}//這里的意思就是如果不夠減就向高位借10,高一位-1,此位+10
a[x]=a1[x]-a2[x];
x++;
}
//減法核心程序
int l=x;
while(a[l]==0&&l>1)
l--;
//如果最高位是0,那么x--以免最高位是0
for(int i=l;i>=1;i--)
cout<<a[i];
cout<<endl;
//收尾(來自蒟蒻的喜悅,前幾次沒成功竟然是因為最后輸出的時候打成i++了,果然是Dai)
return 0;
}
也就我能把這么基礎的東西打75行了,自卑
4 高精度乘法
①算法分析
個人認為這是本次學習最難的地方了(畢竟菜)
但是如果前面的高精度加減法沒有問題的話,這個理解起來也比較簡單。
和前面的思路差不多,我還是從列 豎 式入手
相信各位現在或許還時常能見到這個東西。
我們根據豎式來算的話,就是用a[i]去乘b[1],b[2],b[3]...,然后每次i在變化的時候需要錯位,這個還是比較好想的,讓接收答案的數組c的下標是c[內層循環變量+外層循環變量-1]即可。(當然我最一開始想的時候沒太想通,於是舉了個例子,在這次的高精度學習之中,我個人覺得舉例子是個非常助於理解的方法)
還有一點就是,在進位時的問題,這個也比較好解決。參照剛才加法的方法,可以聲明一個變量x來代表每次進位的數,只不過這里不只是進位1了,而是最多進位9,我們還是可以用當前結果/10的方法來完成計算進位的多少。
實際上分析完這些,乘法也沒有難很多。
②代碼實現
-
輸入數據,和之前一樣。
-
進行乘法運算
- 得到當前的數據,即本次乘積+上次計算結果(最初默認為0)+進位(默認為0)
- 用本次數據求出本次產生進位和本次數據最終結果(即%10)
-
逆序輸出,和之前一樣
這次分析的多了點,上代碼
多理解還是很有用的(至少對我來說),理解了加和減,乘法也能觸類旁通的亞子
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int a[256],b[256],c[256000],x=0;
int main()
{
char s1[256],s2[256];
scanf("%s",s1);
scanf("%s",s2);
int l1=strlen(s1),l2=strlen(s2);
for(int i=0;i<=l1-1;i++)
a[l1-i]=s1[i]-'0';
//沒想到啊,查了15分鍾錯誤,原來是這一行的s1[i]-0 打成了s1[i]=0
for(int i=0;i<=l2-1;i++)
b[l2-i]=s2[i]-'0';
//前邊的就和高精度加減法一樣
for(int i=1;i<=l1;i++)
{
x=0;
for(int p=1;p<=l2;p++)
{
c[i+p-1]=c[i+p-1]+x+(a[i]*b[p]);
//上次處理的數+進位+當前乘積
x=c[i+p-1]/10;
//x是進位數
c[p+i-1]%=10;
//當前結果取余10
}
c[l2+i]=x;
//當內循環結束后,當前進位是下一位
}
//這里是乘法核心程序,注解都在上面了,實際上結合高精度的加減法來說理解起來並不難
int l3=l1+l2;
while(c[l3]==0&&l3>1)
l3--;
for(int i=l3;i>=1;i--)
cout<<c[i];
cout<<endl;
//收尾>o<
return 0;
}
5 總結
本次學習的新知識點
- 對於高精度算法的進一步了解,以及了解其使用的范圍
- 掌握高精度算法的加減乘如何實現
本次學習的感悟
- 要耐心理解,現在知識點的難度不和之前一樣了
本次學習欠缺
- 還沒練題
End
2021.1.28
2915詞
5555字符