




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
第一章高精度計算第一章高精度計算1
利用計算機(jī)進(jìn)行數(shù)值計算,有時會遇到這樣的問題:有些計算要求精度高,希望計算的數(shù)的位數(shù)可達(dá)幾十位甚至幾百位,雖然計算機(jī)的計算精度也算較高了,但因受到硬件的限制,往往達(dá)不到實(shí)際問題所要求的精度。我們可以利用程序設(shè)計的方法去實(shí)現(xiàn)這樣的高精度計算。介紹常用的幾種高精度計算的方法。
高精度計算中需要處理好以下幾個問題:
(1)數(shù)據(jù)的接收方法和存貯方法
數(shù)據(jù)的接收和存貯:當(dāng)輸入的數(shù)很長時,可采用字符串方式輸入,這樣可輸入數(shù)字很長的數(shù),利用字符串函數(shù)和操作運(yùn)算,將每一位數(shù)取出,存入數(shù)組中。另一種方法是直接用循環(huán)加數(shù)組方法輸入數(shù)據(jù)。
voidinit(inta[])
//傳入一個數(shù)組
{
strings;
cin>>s;
//讀入字符串s
a[0]=s.length();//用a[0]計算字符串s的位數(shù)
for(i=1;i<=a[0];i++)
a[i]=s[a[0]-i]-'0';//將數(shù)串s轉(zhuǎn)換為數(shù)組a,并倒序存儲
}另一種方法是直接用循環(huán)加數(shù)組方法輸入數(shù)據(jù)。 利用計算機(jī)進(jìn)行數(shù)值計算,有時會遇到這樣的問2(2)高精度數(shù)位數(shù)的確定位數(shù)的確定:接收時往往是用字符串的,所以它的位數(shù)就等于字符串的長度。(3)進(jìn)位,借位處理
加法進(jìn)位:c[i]=a[i]+b[i];
if(c[i]>=10){c[i]%=10;++c[i+1];}減法借位:if(a[i]<b[i]){--a[i+1];a[i]+=10;}
c[i]=a[i]-b[i];乘法進(jìn)位:c[i+j-1]=a[i]*b[j]+x+c[i+j-1];
x=c[i+j-1]/10;
c[i+j-1]%=10;(4)商和余數(shù)的求法商和余數(shù)處理:視被除數(shù)和除數(shù)的位數(shù)情況進(jìn)行處理.第1章高精度計算(C++版)課件3【例1】高精度加法。輸入兩個正整數(shù),求它們的和。【分析】輸入兩個數(shù)到兩個變量中,然后用賦值語句求它們的和,輸出。但是,我們知道,在C++語言中任何數(shù)據(jù)類型都有一定的表示范圍。而當(dāng)兩個被加數(shù)很大時,上述算法顯然不能求出精確解,因此我們需要尋求另外一種方法。在讀小學(xué)時,我們做加法都采用豎式方法,如圖1。這樣,我們方便寫出兩個整數(shù)相加的算法。856+2551111圖1A3A2A1+B3B2B1
C4C3C2C1圖2如果我們用數(shù)組A、B分別存儲加數(shù)和被加數(shù),用數(shù)組C存儲結(jié)果。則上例有A[1]=6,A[2]=5,A[3]=8,B[1]=5,B[2]=5,B[3]=2,C[4]=1,C[3]=1,C[2]=1,C[1]=1,兩數(shù)相加如圖2所示?!纠?】高精度加法。輸入兩個正整數(shù),求它們的和。84因此,算法描述如下:intc[100];voidadd(inta[],intb[])//a,b,c都為數(shù)組,分別存儲被加數(shù)、加數(shù)、結(jié)果{
inti=1,x=0;
//x是進(jìn)位
while((i<=a數(shù)組長度)||(i<=b數(shù)組的長度)){c[i]=a[i]+b[i]+x; //第i位相加并加上次的進(jìn)位x=c[i]/10;
//向高位進(jìn)位c[i]%=10;//存儲第i位的值i++;
//位置下標(biāo)變量}}因此,算法描述如下:5
通常,讀入的兩個整數(shù)用可用字符串來存儲,程序設(shè)計如下:#include<iostream>#include<cstdio>#include<cstring>usingnamespacestd;intmain(){
chara1[100],b1[100];
inta[100],b[100],c[100],lena,lenb,lenc,i,x;
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
memset(c,0,sizeof(c));
gets(a1);
gets(b1);
//輸入加數(shù)與被加數(shù)
lena=strlen(a1);
lenb=strlen(b1);
for(i=0;i<=lena-1;i++)a[lena-i]=a1[i]-48;
//加數(shù)放入a數(shù)組
for(i=0;i<=lenb-1;i++)b[lenb-i]=b1[i]-48;//加數(shù)放入b數(shù)組
lenc=1;
x=0;
通常,讀入的兩個整數(shù)用可用字符串來存儲,程序設(shè)計如下:6
while(lenc<=lena||lenc<=lenb)
{
c[lenc]=a[lenc]+b[lenc]+x;
//兩數(shù)相加
x=c[lenc]/10;
c[lenc]%=10;
lenc++;
}
c[lenc]=x;
if(c[lenc]==0)
lenc--;//處理最高進(jìn)位
for(i=lenc;i>=1;i--)
cout<<c[i];
//輸出結(jié)果
cout<<endl; return0;} while(lenc<=lena||lenc<=l7【例2】高精度減法。輸入兩個正整數(shù),求它們的差?!舅惴ǚ治觥款愃萍臃?,可以用豎式求減法。在做減法運(yùn)算時,需要注意的是:被減數(shù)必須比減數(shù)大,同時需要處理借位。高精度減法的參考程序:#include<iostream>#include<cstdio>#include<cstring>usingnamespacestd;intmain(){
inta[256],b[256],c[256],lena,lenb,lenc,i;
charn[256],n1[256],n2[256];
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
memset(c,0,sizeof(c));
【例2】高精度減法。輸入兩個正整數(shù),求它們的差。8
printf("Inputminuend:");gets(n1);//輸入被減數(shù)
printf("Inputsubtrahend:");gets(n2);//輸入減數(shù)
if(strlen(n1)<strlen(n2)||(strlen(n1)==strlen(n2)&&strcmp(n1,n2)<0))//strcmp()為字符串比較函數(shù),當(dāng)n1==n2,返回0;//n1>n2時,返回正整數(shù);n1<n2時,返回負(fù)整數(shù)
{//處理被減數(shù)和減數(shù),交換被減數(shù)和減數(shù)
strcpy(n,n1);//將n1數(shù)組的值完全賦值給n數(shù)組
strcpy(n1,n2);
strcpy(n2,n);
cout<<"-";//交換了減數(shù)和被減數(shù),結(jié)果為負(fù)數(shù)
}
lena=strlen(n1);lenb=strlen(n2);
for(i=0;i<=lena-1;i++)a[lena-i]=int(n1[i]-'0');//被減數(shù)放入a數(shù)組
for(i=0;i<=lenb-1;i++)b[lenb-i]=int(n2[i]-'0');//減數(shù)放入b數(shù)組
printf("Inputminuend:");9
i=1;
while(i<=lena||i<=lenb)
{
if(a[i]<b[i])
{
a[i]+=10;//不夠減,那么向高位借1當(dāng)10
a[i+1]--;
}
c[i]=a[i]-b[i];//對應(yīng)位相減
i++;
}
lenc=i;
while((c[lenc]==0)&&(lenc>1))lenc--;//最高位的0不輸出
for(i=lenc;i>=1;i--)cout<<c[i];
//輸出結(jié)果
cout<<endl;
return0;} i=1;10【例3】高精度乘法。輸入兩個正整數(shù),求它們的積?!舅惴ǚ治觥款愃萍臃ǎ梢杂秘Q式求乘法。在做乘法運(yùn)算時,同樣也有進(jìn)位,同時對每一位進(jìn)行乘法運(yùn)算時,必須進(jìn)行錯位相加,如圖3、圖4。分析c數(shù)組下標(biāo)的變化規(guī)律,可以寫出如下關(guān)系式:ci=c’i+c”i+…由此可見,ci跟a[i]*b[j]乘積有關(guān),跟上次的進(jìn)位有關(guān),還跟原ci的值有關(guān),分析下標(biāo)規(guī)律,有c[i+j-1]=a[i]*b[j]+x+c[i+j-1];x=c[i+j-1]/10;c[i+j-1]%=10;856×254280171221400圖3A3A2A1
×B2B1
C’4C’3C’2C’1
C”5C”4C”3C”2
C6C5C4C3C2C1圖4【例3】高精度乘法。輸入兩個正整數(shù),求它們的積。8511高精度乘法的參考程序:#include<iostream>#include<cstring>#include<cstdio>usingnamespacestd;intmain(){
chara1[100],b1[100];
inta[100],b[100],c[100],lena,lenb,lenc,i,j,x;
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
memset(c,0,sizeof(c));
gets(a1);gets(b1);
lena=strlen(a1);lenb=strlen(b1);
for(i=0;i<=lena-1;i++)a[lena-i]=a1[i]-48;
for(i=0;i<=lenb-1;i++)b[lenb-i]=b1[i]-48;
高精度乘法的參考程序:12
for(i=1;i<=lena;i++)
{
x=0;
//用于存放進(jìn)位
for(j=1;j<=lenb;j++)//對乘數(shù)的每一位進(jìn)行處理
{
c[i+j-1]=a[i]*b[j]+x+c[i+j-1];//當(dāng)前乘積+上次乘積進(jìn)位+原數(shù)
x=c[i+j-1]/10;
c[i+j-1]%=10;
}
c[i+lenb]=x;
//進(jìn)位
}
lenc=lena+lenb;
while(c[lenc]==0&&lenc>1)//刪除前導(dǎo)0
lenc--;
for(i=lenc;i>=1;i--)
cout<<c[i];
cout<<endl; return0;} for(i=1;i<=lena;i++)13【例4】高精度除法。輸入兩個正整數(shù),求它們的商(做整除)?!舅惴ǚ治觥孔龀〞r,每一次上商的值都在0~9,每次求得的余數(shù)連接以后的若干位得到新的被除數(shù),繼續(xù)做除法。因此,在做高精度除法時,要涉及到乘法運(yùn)算和減法運(yùn)算,還有移位處理。當(dāng)然,為了程序簡潔,可以避免高精度除法,用0~9次循環(huán)減法取代得到商的值。這里,我們討論一下高精度數(shù)除以單精度數(shù)的結(jié)果,采取的方法是按位相除法?!纠?】高精度除法。輸入兩個正整數(shù),求它們的商(做整除)。14#include<iostream>#include<cstring>#include<cstdio>usingnamespacestd;intmain(){
chara1[100],c1[100];
inta[100],c[100],lena,i,x=0,lenc,b;
memset(a,0,sizeof(a));
memset(c,0,sizeof(c));
gets(a1);
cin>>b;
lena=strlen(a1);
for(i=0;i<=lena-1;i++)
a[i+1]=a1[i]-48;#include<iostream>15
for(i=1;i<=lena;i++)
//按位相除
{
c[i]=(x*10+a[i])/b;
x=(x*10+a[i])%b;
}
lenc=1;
while(c[lenc]==0&&lenc<lena)
lenc++;//刪除前導(dǎo)0
for(i=lenc;i<=lena;i++)
cout<<c[i];
cout<<endl; return0;} for(i=1;i<=lena;i++)16實(shí)質(zhì)上,在做兩個高精度數(shù)運(yùn)算時候,存儲高精度數(shù)的數(shù)組元素可以不僅僅只保留一個數(shù)字,而采取保留多位數(shù)(例如一個整型或長整型數(shù)據(jù)等),這樣,在做運(yùn)算(特別是乘法運(yùn)算)時,可以減少很多操作次數(shù)。例如圖5就是采用4位保存的除法運(yùn)算,其他運(yùn)算也類似。具體程序可以修改上述例題予以解決,程序請讀者完成。示例:123456789÷45=1’2345’6789÷45=274’3484∵1/45=0,1%45=1∴取12345/45=274∵12345%45=15∴取156789/45=3484∴答案為2743484,余數(shù)為156789%45=9圖5實(shí)質(zhì)上,在做兩個高精度數(shù)運(yùn)算時候,存儲高精度數(shù)17
【例5】高精除以高精,求它們的商和余數(shù)。
【算法分析】
高精除以低精是對被除數(shù)的每一位(這里的“一位”包含前面的余數(shù),以下都是如此)都除以除數(shù),而高精除以高精則是用減法模擬除法,對被除數(shù)的每一位都減去除數(shù),一直減到當(dāng)前位置的數(shù)字(包含前面的余數(shù))小于除數(shù)(由于每一位的數(shù)字小于10,所以對于每一位最多進(jìn)行10次計算)具體實(shí)現(xiàn)程序如下: 【例5】高精除以高精,求它們的商和余數(shù)。18
#include<iostream>#include<cstring>usingnamespacestd;inta[101],b[101],c[101],d,i;voidinit(inta[]){
strings;
cin>>s;//讀入字符串s
a[0]=s.length();//用a[0]計算字符串s的位數(shù)
for(i=1;i<=a[0];i++)
a[i]=s[a[0]-i]-'0';//將數(shù)串s轉(zhuǎn)換為數(shù)組a,并倒序存儲.}voidprint(inta[])//打印輸出{
if(a[0]==0){cout<<0<<endl;return;}
for(inti=a[0];i>0;i--)cout<<a[i];
cout<<endl;
return;}#include<iostream>19
intcompare(inta[],intb[])
//比較a和b的大小關(guān)系,若a>b則為1,a<b則為-1,a=b則為0{
if(a[0]>b[0])return1;
//a的位數(shù)大于b則a比b大
if(a[0]<b[0])return-1;
//a的位數(shù)小于b則a比b小
for(i=a[0];i>0;i--)
//從高位到低位比較
{
if(a[i]>b[i])return1;
if(a[i]<b[i])return-1;
}
return0;
//各位都相等則兩數(shù)相等。}voidnumcpy(intp[],intq[],intdet)//復(fù)制p數(shù)組到q數(shù)組從det開始的地方{
for(inti=1;i<=p[0];i++)q[i+det-1]=p[i];
q[0]=p[0]+det-1;}intcompare(inta[],intb[])20
voidjian(inta[],intb[])
//計算a=a-b{
intflag,i;
flag=compare(a,b);//調(diào)用比較函數(shù)判斷大小
if(flag==0){a[0]=0;return;}//相等
if(flag==1)
//大于
{
for(i=1;i<=a[0];i++)
{
if(a[i]<b[i]){a[i+1]--;a[i]+=10;}//若不夠減則向上借一位
a[i]-=b[i];
}
while(a[0]>0&&a[a[0]]==0)a[0]--;
//修正a的位數(shù)
return;
}}voidjian(inta[],intb[])21
voidchugao(inta[],intb[],intc[]){
inttmp[101];
c[0]=a[0]-b[0]+1;
for(inti=c[0];i>0;i--)
{
memset(tmp,0,sizeof(tmp));
//數(shù)組清零
numcpy(b,tmp,i);
while(compare(a,tmp)>=0){c[i]++;jian(a,tmp);}//用減法來模擬
}
while(c[0]>0&&c[c[0]]==0)c[0]--;
return;}voidchugao(inta[],intb[],i22
intmain(){
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
memset(c,0,sizeof(c));
init(a);init(b);
chugao(a,b,c);
print(c);
print(a);
return0;}intmain()23
【例6】回文數(shù)【問題描述】
若一個數(shù)(首位不為零)從左向右讀與從右向左讀都是一樣,我們就將其稱之為回文數(shù)。例如:給定一個10進(jìn)制數(shù)56,將56加65(即把56從右向左讀),得到121是一個回文數(shù)。又如,對于10進(jìn)制數(shù)87,STEPl:87+78=165STEP2:165+561=726STEP3:726+627=1353STEP4:1353+3531=4884在這里的一步是指進(jìn)行了一次N進(jìn)制的加法,上例最少用了4步得到回文數(shù)4884。寫一個程序,給定一個N(2<N<=10或N=16)進(jìn)制數(shù)M.求最少經(jīng)過幾步可以得到回文數(shù)。如果在30步以內(nèi)(包含30步)不可能得到回文數(shù),則輸出“Impossible”【輸入樣例】:987【輸出樣例】:6【算法分析】N進(jìn)制運(yùn)算1、當(dāng)前位規(guī)范由%10改為%n2、進(jìn)位處理由/10改為/n3、其他運(yùn)算規(guī)則不變【例6】回文數(shù)24
【參考程序】#include<iostream>#include<cstring>usingnamespacestd;intn,a[101],b[101],ans,i;voidinit(inta[])
//將數(shù)串s轉(zhuǎn)化為整數(shù)數(shù)組a{
strings;
cin>>n>>s;//讀入字符串s
memset(a,0,sizeof(a));//數(shù)組a清0
a[0]=s.length();//用a[0]計算字符串s的位數(shù)
for(i=1;i<=a[0];i++)
if(s[a[0]-i]>='0'&&s[a[0]-i]<='9')a[i]=s[a[0]-i]-'0';
elsea[i]=s[a[0]-i]-'A'+10;}boolcheck(inta[])//判別整數(shù)數(shù)組a是否為回文數(shù){
for(i=1;i<=a[0];i++)
if(a[i]!=a[a[0]-i+1])returnfalse;
returntrue;}【參考程序】25
voidjia(inta[])//整數(shù)數(shù)組a與其反序數(shù)b進(jìn)行n進(jìn)制加法運(yùn)算{
for(inti=1;i<=a[0];i++)b[i]=a[a[0]-i+1];//反序數(shù)b
for(inti=1;i<=a[0];i++)a[i]+=b[i];//逐位相加
for(inti=1;i<=a[0];i++)
//處理進(jìn)位
{a[i+1]+=a[i]/n;
a[i]%=n;
}
if(a[a[0]+1]>0)a[0]++;//修正新的a的位數(shù)(a+b最多只能的一個進(jìn)位)}intmain(){
init(a);
if(check(a)){cout<<0<<endl;return0;}
ans=0;
//步數(shù)初始化為0
while(ans++<=30)
{
jia(a);
if(check(a)){cout<<ans<<endl;return0;}
}
cout<<"Impossible";//輸出無解信息
return0;}voidjia(inta[])26【上機(jī)練習(xí)】1、求N!的值【問題描述】用高精度方法,求N!的精確值(N以一般整數(shù)輸入)?!据斎霕永縩i.in10【輸出樣例】ni.out36288002、求A/B高精度值【問題描述】計算A/B的精確值,設(shè)A,B是以一般整數(shù)輸入,計算結(jié)果精確小數(shù)后20位?!据斎霕永縜b.in43【輸出樣例】ab.out4/3=1.33333333333333333333【輸入樣例】ab.in65【輸出樣例】ab.out6/5=1.2【上機(jī)練習(xí)】1、求N!的值273、求n累加和【問題描述】用高精度方法,求s=1+2+3+……+n的精確值(n以一般整數(shù)輸入)?!据斎霕永縥a.in
10【輸出樣例】ja.out554、階乘和(sum.pas)【問題描述】已知正整數(shù)N(N<=100),設(shè)S=1!+2!+3!+...N!。其中"!"表示階乘,即N!=1*2*3*……*(N-1)*N,如:3!=1*2*3=6。請編程實(shí)現(xiàn):輸入正整數(shù)N,輸出計算結(jié)果S的值。【輸入樣例】sum.in4【輸出樣例】sum.out335、高精度求積(MULTIPLY.PAS)【問題描述】輸入兩個高精度正整數(shù)M和N(M和N均小于100位)?!締栴}求解】求這兩個高精度數(shù)的積?!据斎霕永縈ULTIPLY.IN363【輸出樣例】MULTIPLY.OUT1083、求n累加和286、天使的起誓(YUBIKILI.pas)【問題描述】TENSHI非常幸運(yùn)的被選為掌管智慧之匙的天使。在正式任職之前,她必須和其他新當(dāng)選的天使一樣,要宣誓。宣誓儀式是每位天使各自表述自己的使命,她們的發(fā)言稿被放在N個呈圓形排列的寶盒中。這些寶盒按順時針方向被編上號碼1、2、3……、N-1、N。一開始天使們站在編號為N的寶盒旁。她們各自手上都有一個數(shù)字,代表她們自己的發(fā)言稿所在的盒子是從1號盒子開始按順時針方向的第幾個。例如:有7個盒子,那么如果TENSHI手上的數(shù)字為9,那么她的發(fā)言稿所在盒子就是第2個。現(xiàn)在天使們開始按照自己手上的數(shù)字來找發(fā)言稿,先找到的就可以先發(fā)言。TENSHI一下子就找到了,于是她最先上臺宣誓:“我將帶領(lǐng)大家開啟NOI之門……”TENSHI宣誓結(jié)束以后,陸續(xù)有天使上臺宣誓??墒怯幸晃惶焓拐伊撕镁枚颊也坏剿陌l(fā)言稿,原來她手上的數(shù)字M非常大,她轉(zhuǎn)了好久都找不到她想找的寶盒。【問題求解】請幫助這位天使找到她想找的寶盒的編號?!据斎敫袷健繌奈募UBIKILI.IN的第一、二行分別讀入正整數(shù)N和M,其中N、M滿足2≤N≤108,2≤M≤101000【輸出格式】把所求寶盒的編號輸出到文件YUBIKILI.OUT,文件只有一行(包括換行符)。樣例一YUBIKILI.IN79YUBIKILI.OUT2樣例二YUBIKILI.IN11108YUBIKILI.OUT96、天使的起誓(YUBIKILI.pas)樣例一YUBIKI297、Hanoi雙塔問題(Noip2007)【問題描述】給定A、B、C三根足夠長的細(xì)柱,在A柱上放有2n個中間有孔的圓盤,共有n個不同的尺寸,每個尺寸都有兩個相同的圓盤,注意這兩個圓盤是不加區(qū)分的(下圖為n=3的情形)?,F(xiàn)要將這些圓盤移到C柱上,在移動過程中可放在B柱上暫存。要求:(1)每次只能移動一個圓盤;(2)A、B、C三根細(xì)柱上的圓盤都要保持上小下大的順序;任務(wù):設(shè)An為2n個圓盤完成上述任務(wù)所需的最少移動次數(shù),對于輸入的n,輸出An?!据斎敫袷健枯斎胛募anoi.in為一個正整數(shù)n,表示在A柱上放有2n個圓盤?!据敵龈袷健枯敵鑫募anoi.out僅一行,包含一個正整數(shù),為完成上述任務(wù)所需的最少移動次數(shù)An。樣例一hanoi.in
1hanoi.out2樣例二hanoi.inhanoi.out26【限制】對于50%的數(shù)據(jù),1<=n<=25對于100%的數(shù)據(jù),1<=n<=200【提示】設(shè)法建立An與An-1的遞推關(guān)系式。7、Hanoi雙塔問題(Noip2007)【輸入格式】樣例一30第一章高精度計算第一章高精度計算31
利用計算機(jī)進(jìn)行數(shù)值計算,有時會遇到這樣的問題:有些計算要求精度高,希望計算的數(shù)的位數(shù)可達(dá)幾十位甚至幾百位,雖然計算機(jī)的計算精度也算較高了,但因受到硬件的限制,往往達(dá)不到實(shí)際問題所要求的精度。我們可以利用程序設(shè)計的方法去實(shí)現(xiàn)這樣的高精度計算。介紹常用的幾種高精度計算的方法。
高精度計算中需要處理好以下幾個問題:
(1)數(shù)據(jù)的接收方法和存貯方法
數(shù)據(jù)的接收和存貯:當(dāng)輸入的數(shù)很長時,可采用字符串方式輸入,這樣可輸入數(shù)字很長的數(shù),利用字符串函數(shù)和操作運(yùn)算,將每一位數(shù)取出,存入數(shù)組中。另一種方法是直接用循環(huán)加數(shù)組方法輸入數(shù)據(jù)。
voidinit(inta[])
//傳入一個數(shù)組
{
strings;
cin>>s;
//讀入字符串s
a[0]=s.length();//用a[0]計算字符串s的位數(shù)
for(i=1;i<=a[0];i++)
a[i]=s[a[0]-i]-'0';//將數(shù)串s轉(zhuǎn)換為數(shù)組a,并倒序存儲
}另一種方法是直接用循環(huán)加數(shù)組方法輸入數(shù)據(jù)。 利用計算機(jī)進(jìn)行數(shù)值計算,有時會遇到這樣的問32(2)高精度數(shù)位數(shù)的確定位數(shù)的確定:接收時往往是用字符串的,所以它的位數(shù)就等于字符串的長度。(3)進(jìn)位,借位處理
加法進(jìn)位:c[i]=a[i]+b[i];
if(c[i]>=10){c[i]%=10;++c[i+1];}減法借位:if(a[i]<b[i]){--a[i+1];a[i]+=10;}
c[i]=a[i]-b[i];乘法進(jìn)位:c[i+j-1]=a[i]*b[j]+x+c[i+j-1];
x=c[i+j-1]/10;
c[i+j-1]%=10;(4)商和余數(shù)的求法商和余數(shù)處理:視被除數(shù)和除數(shù)的位數(shù)情況進(jìn)行處理.第1章高精度計算(C++版)課件33【例1】高精度加法。輸入兩個正整數(shù),求它們的和?!痉治觥枯斎雰蓚€數(shù)到兩個變量中,然后用賦值語句求它們的和,輸出。但是,我們知道,在C++語言中任何數(shù)據(jù)類型都有一定的表示范圍。而當(dāng)兩個被加數(shù)很大時,上述算法顯然不能求出精確解,因此我們需要尋求另外一種方法。在讀小學(xué)時,我們做加法都采用豎式方法,如圖1。這樣,我們方便寫出兩個整數(shù)相加的算法。856+2551111圖1A3A2A1+B3B2B1
C4C3C2C1圖2如果我們用數(shù)組A、B分別存儲加數(shù)和被加數(shù),用數(shù)組C存儲結(jié)果。則上例有A[1]=6,A[2]=5,A[3]=8,B[1]=5,B[2]=5,B[3]=2,C[4]=1,C[3]=1,C[2]=1,C[1]=1,兩數(shù)相加如圖2所示?!纠?】高精度加法。輸入兩個正整數(shù),求它們的和。834因此,算法描述如下:intc[100];voidadd(inta[],intb[])//a,b,c都為數(shù)組,分別存儲被加數(shù)、加數(shù)、結(jié)果{
inti=1,x=0;
//x是進(jìn)位
while((i<=a數(shù)組長度)||(i<=b數(shù)組的長度)){c[i]=a[i]+b[i]+x; //第i位相加并加上次的進(jìn)位x=c[i]/10;
//向高位進(jìn)位c[i]%=10;//存儲第i位的值i++;
//位置下標(biāo)變量}}因此,算法描述如下:35
通常,讀入的兩個整數(shù)用可用字符串來存儲,程序設(shè)計如下:#include<iostream>#include<cstdio>#include<cstring>usingnamespacestd;intmain(){
chara1[100],b1[100];
inta[100],b[100],c[100],lena,lenb,lenc,i,x;
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
memset(c,0,sizeof(c));
gets(a1);
gets(b1);
//輸入加數(shù)與被加數(shù)
lena=strlen(a1);
lenb=strlen(b1);
for(i=0;i<=lena-1;i++)a[lena-i]=a1[i]-48;
//加數(shù)放入a數(shù)組
for(i=0;i<=lenb-1;i++)b[lenb-i]=b1[i]-48;//加數(shù)放入b數(shù)組
lenc=1;
x=0;
通常,讀入的兩個整數(shù)用可用字符串來存儲,程序設(shè)計如下:36
while(lenc<=lena||lenc<=lenb)
{
c[lenc]=a[lenc]+b[lenc]+x;
//兩數(shù)相加
x=c[lenc]/10;
c[lenc]%=10;
lenc++;
}
c[lenc]=x;
if(c[lenc]==0)
lenc--;//處理最高進(jìn)位
for(i=lenc;i>=1;i--)
cout<<c[i];
//輸出結(jié)果
cout<<endl; return0;} while(lenc<=lena||lenc<=l37【例2】高精度減法。輸入兩個正整數(shù),求它們的差。【算法分析】類似加法,可以用豎式求減法。在做減法運(yùn)算時,需要注意的是:被減數(shù)必須比減數(shù)大,同時需要處理借位。高精度減法的參考程序:#include<iostream>#include<cstdio>#include<cstring>usingnamespacestd;intmain(){
inta[256],b[256],c[256],lena,lenb,lenc,i;
charn[256],n1[256],n2[256];
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
memset(c,0,sizeof(c));
【例2】高精度減法。輸入兩個正整數(shù),求它們的差。38
printf("Inputminuend:");gets(n1);//輸入被減數(shù)
printf("Inputsubtrahend:");gets(n2);//輸入減數(shù)
if(strlen(n1)<strlen(n2)||(strlen(n1)==strlen(n2)&&strcmp(n1,n2)<0))//strcmp()為字符串比較函數(shù),當(dāng)n1==n2,返回0;//n1>n2時,返回正整數(shù);n1<n2時,返回負(fù)整數(shù)
{//處理被減數(shù)和減數(shù),交換被減數(shù)和減數(shù)
strcpy(n,n1);//將n1數(shù)組的值完全賦值給n數(shù)組
strcpy(n1,n2);
strcpy(n2,n);
cout<<"-";//交換了減數(shù)和被減數(shù),結(jié)果為負(fù)數(shù)
}
lena=strlen(n1);lenb=strlen(n2);
for(i=0;i<=lena-1;i++)a[lena-i]=int(n1[i]-'0');//被減數(shù)放入a數(shù)組
for(i=0;i<=lenb-1;i++)b[lenb-i]=int(n2[i]-'0');//減數(shù)放入b數(shù)組
printf("Inputminuend:");39
i=1;
while(i<=lena||i<=lenb)
{
if(a[i]<b[i])
{
a[i]+=10;//不夠減,那么向高位借1當(dāng)10
a[i+1]--;
}
c[i]=a[i]-b[i];//對應(yīng)位相減
i++;
}
lenc=i;
while((c[lenc]==0)&&(lenc>1))lenc--;//最高位的0不輸出
for(i=lenc;i>=1;i--)cout<<c[i];
//輸出結(jié)果
cout<<endl;
return0;} i=1;40【例3】高精度乘法。輸入兩個正整數(shù),求它們的積?!舅惴ǚ治觥款愃萍臃?,可以用豎式求乘法。在做乘法運(yùn)算時,同樣也有進(jìn)位,同時對每一位進(jìn)行乘法運(yùn)算時,必須進(jìn)行錯位相加,如圖3、圖4。分析c數(shù)組下標(biāo)的變化規(guī)律,可以寫出如下關(guān)系式:ci=c’i+c”i+…由此可見,ci跟a[i]*b[j]乘積有關(guān),跟上次的進(jìn)位有關(guān),還跟原ci的值有關(guān),分析下標(biāo)規(guī)律,有c[i+j-1]=a[i]*b[j]+x+c[i+j-1];x=c[i+j-1]/10;c[i+j-1]%=10;856×254280171221400圖3A3A2A1
×B2B1
C’4C’3C’2C’1
C”5C”4C”3C”2
C6C5C4C3C2C1圖4【例3】高精度乘法。輸入兩個正整數(shù),求它們的積。8541高精度乘法的參考程序:#include<iostream>#include<cstring>#include<cstdio>usingnamespacestd;intmain(){
chara1[100],b1[100];
inta[100],b[100],c[100],lena,lenb,lenc,i,j,x;
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
memset(c,0,sizeof(c));
gets(a1);gets(b1);
lena=strlen(a1);lenb=strlen(b1);
for(i=0;i<=lena-1;i++)a[lena-i]=a1[i]-48;
for(i=0;i<=lenb-1;i++)b[lenb-i]=b1[i]-48;
高精度乘法的參考程序:42
for(i=1;i<=lena;i++)
{
x=0;
//用于存放進(jìn)位
for(j=1;j<=lenb;j++)//對乘數(shù)的每一位進(jìn)行處理
{
c[i+j-1]=a[i]*b[j]+x+c[i+j-1];//當(dāng)前乘積+上次乘積進(jìn)位+原數(shù)
x=c[i+j-1]/10;
c[i+j-1]%=10;
}
c[i+lenb]=x;
//進(jìn)位
}
lenc=lena+lenb;
while(c[lenc]==0&&lenc>1)//刪除前導(dǎo)0
lenc--;
for(i=lenc;i>=1;i--)
cout<<c[i];
cout<<endl; return0;} for(i=1;i<=lena;i++)43【例4】高精度除法。輸入兩個正整數(shù),求它們的商(做整除)?!舅惴ǚ治觥孔龀〞r,每一次上商的值都在0~9,每次求得的余數(shù)連接以后的若干位得到新的被除數(shù),繼續(xù)做除法。因此,在做高精度除法時,要涉及到乘法運(yùn)算和減法運(yùn)算,還有移位處理。當(dāng)然,為了程序簡潔,可以避免高精度除法,用0~9次循環(huán)減法取代得到商的值。這里,我們討論一下高精度數(shù)除以單精度數(shù)的結(jié)果,采取的方法是按位相除法?!纠?】高精度除法。輸入兩個正整數(shù),求它們的商(做整除)。44#include<iostream>#include<cstring>#include<cstdio>usingnamespacestd;intmain(){
chara1[100],c1[100];
inta[100],c[100],lena,i,x=0,lenc,b;
memset(a,0,sizeof(a));
memset(c,0,sizeof(c));
gets(a1);
cin>>b;
lena=strlen(a1);
for(i=0;i<=lena-1;i++)
a[i+1]=a1[i]-48;#include<iostream>45
for(i=1;i<=lena;i++)
//按位相除
{
c[i]=(x*10+a[i])/b;
x=(x*10+a[i])%b;
}
lenc=1;
while(c[lenc]==0&&lenc<lena)
lenc++;//刪除前導(dǎo)0
for(i=lenc;i<=lena;i++)
cout<<c[i];
cout<<endl; return0;} for(i=1;i<=lena;i++)46實(shí)質(zhì)上,在做兩個高精度數(shù)運(yùn)算時候,存儲高精度數(shù)的數(shù)組元素可以不僅僅只保留一個數(shù)字,而采取保留多位數(shù)(例如一個整型或長整型數(shù)據(jù)等),這樣,在做運(yùn)算(特別是乘法運(yùn)算)時,可以減少很多操作次數(shù)。例如圖5就是采用4位保存的除法運(yùn)算,其他運(yùn)算也類似。具體程序可以修改上述例題予以解決,程序請讀者完成。示例:123456789÷45=1’2345’6789÷45=274’3484∵1/45=0,1%45=1∴取12345/45=274∵12345%45=15∴取156789/45=3484∴答案為2743484,余數(shù)為156789%45=9圖5實(shí)質(zhì)上,在做兩個高精度數(shù)運(yùn)算時候,存儲高精度數(shù)47
【例5】高精除以高精,求它們的商和余數(shù)。
【算法分析】
高精除以低精是對被除數(shù)的每一位(這里的“一位”包含前面的余數(shù),以下都是如此)都除以除數(shù),而高精除以高精則是用減法模擬除法,對被除數(shù)的每一位都減去除數(shù),一直減到當(dāng)前位置的數(shù)字(包含前面的余數(shù))小于除數(shù)(由于每一位的數(shù)字小于10,所以對于每一位最多進(jìn)行10次計算)具體實(shí)現(xiàn)程序如下: 【例5】高精除以高精,求它們的商和余數(shù)。48
#include<iostream>#include<cstring>usingnamespacestd;inta[101],b[101],c[101],d,i;voidinit(inta[]){
strings;
cin>>s;//讀入字符串s
a[0]=s.length();//用a[0]計算字符串s的位數(shù)
for(i=1;i<=a[0];i++)
a[i]=s[a[0]-i]-'0';//將數(shù)串s轉(zhuǎn)換為數(shù)組a,并倒序存儲.}voidprint(inta[])//打印輸出{
if(a[0]==0){cout<<0<<endl;return;}
for(inti=a[0];i>0;i--)cout<<a[i];
cout<<endl;
return;}#include<iostream>49
intcompare(inta[],intb[])
//比較a和b的大小關(guān)系,若a>b則為1,a<b則為-1,a=b則為0{
if(a[0]>b[0])return1;
//a的位數(shù)大于b則a比b大
if(a[0]<b[0])return-1;
//a的位數(shù)小于b則a比b小
for(i=a[0];i>0;i--)
//從高位到低位比較
{
if(a[i]>b[i])return1;
if(a[i]<b[i])return-1;
}
return0;
//各位都相等則兩數(shù)相等。}voidnumcpy(intp[],intq[],intdet)//復(fù)制p數(shù)組到q數(shù)組從det開始的地方{
for(inti=1;i<=p[0];i++)q[i+det-1]=p[i];
q[0]=p[0]+det-1;}intcompare(inta[],intb[])50
voidjian(inta[],intb[])
//計算a=a-b{
intflag,i;
flag=compare(a,b);//調(diào)用比較函數(shù)判斷大小
if(flag==0){a[0]=0;return;}//相等
if(flag==1)
//大于
{
for(i=1;i<=a[0];i++)
{
if(a[i]<b[i]){a[i+1]--;a[i]+=10;}//若不夠減則向上借一位
a[i]-=b[i];
}
while(a[0]>0&&a[a[0]]==0)a[0]--;
//修正a的位數(shù)
return;
}}voidjian(inta[],intb[])51
voidchugao(inta[],intb[],intc[]){
inttmp[101];
c[0]=a[0]-b[0]+1;
for(inti=c[0];i>0;i--)
{
memset(tmp,0,sizeof(tmp));
//數(shù)組清零
numcpy(b,tmp,i);
while(compare(a,tmp)>=0){c[i]++;jian(a,tmp);}//用減法來模擬
}
while(c[0]>0&&c[c[0]]==0)c[0]--;
return;}voidchugao(inta[],intb[],i52
intmain(){
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
memset(c,0,sizeof(c));
init(a);init(b);
chugao(a,b,c);
print(c);
print(a);
return0;}intmain()53
【例6】回文數(shù)【問題描述】
若一個數(shù)(首位不為零)從左向右讀與從右向左讀都是一樣,我們就將其稱之為回文數(shù)。例如:給定一個10進(jìn)制數(shù)56,將56加65(即把56從右向左讀),得到121是一個回文數(shù)。又如,對于10進(jìn)制數(shù)87,STEPl:87+78=165STEP2:165+561=726STEP3:726+627=1353STEP4:1353+3531=4884在這里的一步是指進(jìn)行了一次N進(jìn)制的加法,上例最少用了4步得到回文數(shù)4884。寫一個程序,給定一個N(2<N<=10或N=16)進(jìn)制數(shù)M.求最少經(jīng)過幾步可以得到回文數(shù)。如果在30步以內(nèi)(包含30步)不可能得到回文數(shù),則輸出“Impossible”【輸入樣例】:987【輸出樣例】:6【算法分析】N進(jìn)制運(yùn)算1、當(dāng)前位規(guī)范由%10改為%n2、進(jìn)位處理由/10改為/n3、其他運(yùn)算規(guī)則不變【例6】回文數(shù)54
【參考程序】#include<iostream>#include<cstring>usingnamespacestd;intn,a[101],b[101],ans,i;voidinit(inta[])
//將數(shù)串s轉(zhuǎn)化為整數(shù)數(shù)組a{
strings;
cin>>n>>s;//讀入字符串s
memset(a,0,sizeof(a));//數(shù)組a清0
a[0]=s.length();//用a[0]計算字符串s的位數(shù)
for(i=1;i<=a[0];i++)
if(s[a[0]-i]>='0'&&s[a[0]-i]<='9')a[i]=s[a[0]-i]-'0';
elsea[i]=s[a[0]-i]-'A'+10;}boolcheck(inta[])//判別整數(shù)數(shù)組a是否為回文數(shù){
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 倉儲設(shè)備租賃合同協(xié)議書
- 人工智能技術(shù)應(yīng)用研發(fā)合作協(xié)議
- 鋼筋焊接施工承包合同
- 工程承包合同單價合同
- 企業(yè)信息化戰(zhàn)略規(guī)劃與實(shí)施
- 工廠場地租賃合同
- 電子商務(wù)購銷合同
- 數(shù)據(jù)安全與信息保密服務(wù)協(xié)議
- 血液(第二課時)課件2024-2025學(xué)年北師大版生物七年級下冊
- 關(guān)于調(diào)整辦公環(huán)境的申請通知
- 2025春-新版一年級語文下冊生字表(200個)
- 護(hù)士法律法規(guī)知識培訓(xùn)
- 《職業(yè)流行病學(xué)》課件
- 2025年全國幼兒園教師資格證考試教育理論知識押題試題庫及答案(共九套)
- 精神科病人安全與治療管理制度
- 2024年外貿(mào)業(yè)務(wù)員個人年度工作總結(jié)
- 關(guān)愛留守兒童培訓(xùn)
- 金融數(shù)學(xué)布朗運(yùn)動
- 第三單元名著閱讀《經(jīng)典常談》課件 2023-2024學(xué)年統(tǒng)編版語文八年級下冊11.22
- 江西省上饒市余干縣沙港中學(xué)2024-2025學(xué)年八年級上學(xué)期競賽生物學(xué)試卷(無答案)
- 神經(jīng)外科主要治病
評論
0/150
提交評論