C語言-浮點類型
浮點類型
在0的兩側有一小塊區域,這個區域非常接近0,但是不等於0,是float(表達范圍數量級10-38)或者double(達范圍數量級10-308)無法表達的,而0是可以表達的;nan:不是一個有效的數字。有效數字:在有效數字范圍是精確的,超出這個范圍是不准確的。
%e:輸出科學計數法的形式,%E只是表示時字母大寫。
在使用科學計數法時,數字與E或者e之間不要有任何空格。小數點位數較多時,double有時顯示不出來小數位的數字如1E-10,以double輸出時只是0.000000,想要看到1,在printf可以指定輸出的位數,如使用%.16f。所以可以在%和f之間加上.n可以指定輸出小數點后幾位,這樣的輸出時做四舍六入五成雙的規則。
printf("%.3f\n",-0.0049) 結果保留3位 -> 0.005
printf("%.30f\n",-0.0049) 結果保留30位 -> 0.004899999999...
printf("%.3f\n",-0.00049) 結果保留3位 -> 0.000
printf("%.3f\n",-0.0045) 結果保留3位 -> 0.0004
第二種實際上是計算機內部真實的情況,-0.0049實際不能被計算機精確的表達為-0.0049。
雖然理論上來說數是連續的,也就是說,任意取兩個點,你可以在兩個點之間獲得任意多的數,數量是無限的(實數的稠密性),但對計算機來說,只能用離散的數字來表達數字,位於兩個緊鄰的數字之前的數字是數據類型如double,不能表達的。當你寫出0.0049的時候,而這個數恰好是所能表達的兩個數之間的數字,我們就必須選擇離它最近的那個數字來表達它,但它和實際的0.0049是有段距離的,而這個距離就是浮點數誤差。
第四種里的0.0045其實是0.00449... ,是個很接近0.0045的數字
浮點數的范圍與精度
超過范圍的浮點數
printf輸出inf表示超過范圍的浮點數:+- ∞
printf輸出nan表示不存在的浮點數
浮點正數除以0結果是正inf;浮點負數除以0結果為-inf,浮點0除以0是nan。
但需注意:整數除以0,結果報錯。因為無窮大無法用整數來表達,但無窮大可以用浮點數來表達,雖然浮點有效范圍內部包含無窮大,但是在浮點數的設計里,把無窮大,nan定義在浮點數里面。同時注意浮點的運算是沒有精度的。做個簡單的實驗:
#include <stdio.h>
int main()
{
float a,b,c;
a = 1.345f;
//f表示一個float型浮點數,不帶的話,C默認浮點數類型是double類型
b = 1.123f;
c = a + b;
if (c == 2.468)
printf("相等\n");
else
printf("不相等!c=%.10f,或%f\n",c,c);
return 0;
}
//結果:不相等!c=2.4679999352(實際只有7位有效2.467999),或2.468000
這里雖然前面聲明了float類型,但是在下面表示float也要加上f,否則報錯
- 帶小數點的字面量是double而非float
- float需要用f或F后綴來表明身份
- 兩個float直接用==來判斷可能失敗
- fabs(f1-f2) < 1e-8或1e-12(7個有效數字就可以)來判斷是否相等。所以不要用浮點數來做一些精確的運算。特別是金錢的運算,例如1.23元和1.34元相加減等,這些誤差會累積,解決的簡單方法是換算成整數再運算,整數永遠都是精確的,所以可以把1.23元換成123分。浮點數只能在一定的范圍內相信它。
浮點數的內部表達
整數是純二進制來表達的,所以兩個浮點數可以直接做運算,而浮點數則不同,其背部是一種編碼的形式。
一個bit來表達正負數,11個bit來表達指數部分是多少,后面用來表達分數部分是多少,但這里未必把所有的bit都用完。
浮點數在計算時是由專用的硬件部分(協處理器,現在基本都集成到CPU中了)來實現的,計算時將編碼交給專門的硬件,硬件會把其解開來,然后來計算,計算后再編碼成這樣的數字給你。計算double和float所用的部件是一樣的。
選擇浮點類型
- 如果沒有特殊需要,只使用double
- 現代CPU能直接對double做硬件運算,性能不會比float差,在64位的機器上,數據存儲的速度也不比float慢。