摘要:使用C語(yǔ)言編程進(jìn)行計(jì)算的時(shí)候常常會(huì)因?yàn)椴蛔⒁忸愋娃D(zhuǎn)換產(chǎn)生問(wèn)題,尤其是在使用除法運(yùn)算符“/”的時(shí)候,經(jīng)常因?yàn)闆](méi)有注意運(yùn)算數(shù)據(jù)類型轉(zhuǎn)換,從而導(dǎo)致運(yùn)算結(jié)果不正確或著說(shuō)是精度不夠的問(wèn)題。以下就C語(yǔ)言中“/”影響運(yùn)算精度的問(wèn)題做簡(jiǎn)單的探討,希望助于初學(xué)者甚至是有一定編程水平的人更好地使用C語(yǔ)言。
關(guān)鍵詞:C語(yǔ)言;精度;除法運(yùn)算符
中圖分類號(hào):TP311文獻(xiàn)標(biāo)識(shí)碼:A文章編號(hào):1009-3044(2008)30-0604-02
Affect Arithmetic Accuracy Problem Investigation and Discussion in C Language
CHEN Jie, DANG Qun
(Northeastern University at Qinhuangdao (Computer Engineering),Qinhuangdao 066004,China)
Abstract: Using the C language programming to be in progress when secretly scheming against often may produce problem because of not paying attention to a type change , when using the division arithmetic magic figure\" especially, change , lead to thereby arithmetic result block of wood rightness or insufficient problems of accuracy often because of not paying attention to the arithmetic data type. The problem \"affecting arithmetic accuracy's hereinafter right away in C language\" makes simple investigation and discussion , hopes that aiding in the beginner is that the horizontal people of Cheng uses C language much better even have one to delimit organizational structure.
Key words: C language; accuracy; division operator
1 引言
C語(yǔ)言中除法運(yùn)算符(“/”)是一個(gè)雙目運(yùn)算符,雖然它的運(yùn)算規(guī)則比較簡(jiǎn)單,但是在實(shí)際的編程中,許多人也會(huì)因?yàn)闆](méi)能很好地理解它,從而導(dǎo)致計(jì)算的結(jié)果精度不夠的問(wèn)題。下面我們從除法運(yùn)算符最簡(jiǎn)單的規(guī)則開(kāi)始探討,從而讓C 語(yǔ)言初學(xué)者甚至是有一定編程水平的人能夠正確地使用“/”運(yùn)算符。
2 C語(yǔ)言程序中的“/”運(yùn)算符與數(shù)學(xué)中的“/”的不同
先來(lái)看一個(gè)求平均值的例子:
main()
{int a,b,c;
float ave;
scanf(“%d,%d,%d”,a,b,c);
ave=(a+b+c)/3;
printf(“ave=%f\”,ave);
}
從數(shù)學(xué)的角度來(lái)看這個(gè)程序完全正確,然而當(dāng)你多輸入幾組數(shù)據(jù)測(cè)試的時(shí)候,你會(huì)發(fā)現(xiàn)運(yùn)行的結(jié)果并不是理論上的結(jié)果。比如輸入:1,4,5 三個(gè)數(shù),然而輸出結(jié)果卻是:ave=3.000000,這顯然不是我們想要的結(jié)果:3.333333。這是為什么呢?這就涉及到“/”運(yùn)算符的規(guī)則問(wèn)題了。
3 “/”運(yùn)算符的規(guī)則
3.1 類型轉(zhuǎn)換
C語(yǔ)言中規(guī)定:相同類型的數(shù)據(jù)才可以直接進(jìn)行運(yùn)算,其結(jié)果還是原數(shù)據(jù)類型。而當(dāng)不同的數(shù)據(jù)類型進(jìn)行運(yùn)算時(shí),需要將數(shù)據(jù)轉(zhuǎn)換成同一數(shù)據(jù)類型,然后才可以進(jìn)行運(yùn)算。轉(zhuǎn)換可以通過(guò)兩種方式實(shí)現(xiàn):
3.1.1 數(shù)據(jù)類型的隱含轉(zhuǎn)換
當(dāng)不同類型進(jìn)行運(yùn)算時(shí),要先轉(zhuǎn)為精度較高類型,然后進(jìn)行運(yùn)算。默認(rèn)以下順序由低到高轉(zhuǎn)換:
3.1.2 數(shù)據(jù)類型的強(qiáng)制轉(zhuǎn)換
程序員也可以強(qiáng)制性地改變數(shù)據(jù)的類型,一般格式為:(類型標(biāo)識(shí)符)(表達(dá)式)。如(float)(x+y)表示將表達(dá)式x+y的值轉(zhuǎn)換成float型。需要注意的是:在強(qiáng)制型轉(zhuǎn)換時(shí),會(huì)得到一個(gè)指定類型的中間變量,原來(lái)變量的類型并未發(fā)生改變。比如:(int)a如果a原定義為float型,進(jìn)行強(qiáng)制類型轉(zhuǎn)換后得到一個(gè)int 型的中間變量,它的值等于a的整數(shù)部分,而a的類型不變(仍為float型)。
3.2 整型數(shù)和實(shí)型數(shù)的除法運(yùn)算
從剛才的論述中我們很容易理解一個(gè)C語(yǔ)言規(guī)則:當(dāng)“/”兩邊的操作數(shù)均為整型時(shí),所得結(jié)果也是一個(gè)整型;當(dāng)“/”兩邊的操作數(shù)只要有一個(gè)為實(shí)型時(shí),則運(yùn)算結(jié)果為實(shí)型。在C語(yǔ)言中,整數(shù)除法運(yùn)算結(jié)果的小數(shù)部分都被丟棄,這個(gè)過(guò)程被稱為截尾(truncation)。沒(méi)有把整數(shù)除法運(yùn)算的結(jié)果四舍五入到最近的整數(shù),而是進(jìn)行截尾,即舍棄整個(gè)小數(shù)部分,若要強(qiáng)制性地用float型輸出,小數(shù)部分也全部為0。
現(xiàn)在再來(lái)看上例,a,b,c均為int型,所以a+b+c也為int型,而3也是int型則(a+b+c)/3也應(yīng)為int型,表達(dá)式將運(yùn)算結(jié)果賦給float型變量ave,所以運(yùn)算結(jié)果3以實(shí)數(shù)3.000000的形式放在ave中,并以“%f”的格式輸出,則輸出結(jié)果當(dāng)然為3.000000。此程序可將3改為3.0,則可輸出正確結(jié)果:3.333333。
4 實(shí)例分析
例1:請(qǐng)看以下程序
main()
{int a=35;
float b;
b=a/2;
printf(“%f”,b);
}
輸出結(jié)果:17.0 00000
分析:在此程序中兩操作數(shù)a和2均為int型,運(yùn)算結(jié)果當(dāng)然也為int型。程序?qū)⑦\(yùn)算結(jié)果賦給float 型變量b,所以運(yùn)算結(jié)果17以實(shí)數(shù)17.000000的形式存放在b中,并以%f的格式輸出,則輸出結(jié)果為17.000000 。
顯然這個(gè)程序不能保證運(yùn)算的精度。若要保證運(yùn)算精度,可以將語(yǔ)句“b=a/2;”改為“b=a/2.0;”或“b=(float)a/2;”,此時(shí)兩操作數(shù)在運(yùn)算前轉(zhuǎn)換為實(shí)型,所以運(yùn)算結(jié)果也為實(shí)型,所以輸出結(jié)果為:17.500000 。
例2:4*3/2 不滿足結(jié)合律
在數(shù)學(xué)中4*3/2同4*(3/2)的結(jié)果是相同的,而在C語(yǔ)言中則不同:
main()
{int a,b;
a= 4*3/2;
b=4*(3/2);
printf(“%d,”,a);
printf(“%d”,b);
}
輸出結(jié)果是:6,4
分析:在第一個(gè)輸出語(yǔ)句中,先運(yùn)算4*3得到12,然后在用12整除以2,然后以整型輸出,所以得到結(jié)果:6。而在第二個(gè)輸出語(yǔ)句中,由于()的優(yōu)先級(jí)大于*,則先運(yùn)算“3/2”,而3和2是int型,所以3/2的運(yùn)算結(jié)果為1,然后再與4相乘得到輸出結(jié)果:4,結(jié)果不正確??蓪ⅲ掣臑?.0,則操作數(shù)在運(yùn)算前將類型轉(zhuǎn)換為實(shí)型,最后以整型輸出,則可得運(yùn)算結(jié)果得:6。
例3:輸入一個(gè)數(shù)n,求 1到n的每個(gè)數(shù)的階乘的倒數(shù)的和(sum=1/1!+1/2!+1/3!+…+1/n!) 。
main()
{int i;
unsigned n;
long p=1;
float sum=0.000000;
printf(“please enter anumber:”);
scanf (“%u”,n);
for(i=1;i<=n;i++)
{p=p*i;
sum=sum+1/p;
}
printf(“sum=%f”,sum);
}
顯然無(wú)論輸入什么正整數(shù)結(jié)果均為1.000000,因?yàn)槌绦驁?zhí)行到“sum=sum+1/p;”這條語(yǔ)句的時(shí)候,由于1和p都是int型,所以當(dāng)p大于2的時(shí),1/p就始終為0了,所以最終結(jié)果為1。若想保證精度,則可以 把i定義為float型或?qū)⒀h(huán)中的“sum=sum+1/p;”改為“sum=sum+1.0/p;”,無(wú)論怎樣,要保證1和p中至少有一個(gè)為實(shí)型,才能得出理想的結(jié)果。
以上程序是以Turbo C 環(huán)境為標(biāo)準(zhǔn)。
5 結(jié)束語(yǔ)
在C語(yǔ)言中,如果沒(méi)有很好的理解類型轉(zhuǎn)換,那么在實(shí)際的編程中就會(huì)出現(xiàn)很多的漏洞。特別是在除法運(yùn)算的時(shí)候,很多人都直接用int型除以int型,導(dǎo)致了得到了許多不理想的結(jié)果。所以在實(shí)際的編程中,一定要注意除法運(yùn)算符精度問(wèn)題。
參考文獻(xiàn):
[1] 譚浩強(qiáng).C語(yǔ)言程序設(shè)計(jì)[M].2版.北京:清華大學(xué)出版社,2002.
[2] Stephen prata.primer plus[M].5版,中文版.云巔工作室,譯.北京:人民郵電出版社,2005.
[3] 黨群.C語(yǔ)言程序設(shè)計(jì)[M].沈陽(yáng):東北大學(xué)出版社,2005.
注:本文中所涉及到的圖表、注解、公式等內(nèi)容請(qǐng)以PDF格式閱讀原文