C語言中的小數(float,double)
小數分為整數部分和小數部分,它們由點號.分隔,例如 0.0、75.0、4.023、0.27、-937.198 -0.27 等都是合法的小數,這是最常見的小數形式,我們將它稱為十進位制形式。
此外,小數也可以採用指數形式,例如 7.25×102、0.0368×105、100.22×10-2、-27.36×10-3 等。任何小數都可以用指數形式來表示。
C語言同時支援以上兩種形式的小數。但是在書寫時,C語言中的指數形式和數學中的指數形式有所差異。
C語言中小數的指數形式為:
aEn 或 aena 為尾數部分,是一個十進位制數;n 為指數部分,是一個十進位制整數;E或e是固定的字元,用於分割尾數部分和指數部分。整個表示式等價於 a×10n
指數形式的小數舉例:
- 2.1E5 = 2.1×105,其中 2.1 是尾數,5 是指數。
- 3.7E-2 = 3.7×10-2,其中 3.7 是尾數,-2 是指數。
- 0.5E7 = 0.5×107,其中 0.5 是尾數,7 是指數。
C語言中常用的小數有兩種型別,分別是 float 或 double;float 稱為單精度浮點型,double 稱為雙精度浮點型。
不像整數,小數沒有那麼多么蛾子,小數的長度是固定的,float 始終佔用4個位元組,double 始終佔用8個位元組。
小數的輸出
小數也可以使用 printf 函式輸出,包括十進位制形式和指數形式,它們對應的格式控制符分別是:
- %f 以十進位制形式輸出 float 型別;
- %lf 以十進位制形式輸出 double 型別;
- %e 以指數形式輸出 float 型別,輸出結果中的 e 小寫;
- %E 以指數形式輸出 float 型別,輸出結果中的 E 大寫;
- %le 以指數形式輸出 double 型別,輸出結果中的 e 小寫;
- %lE 以指數形式輸出 double 型別,輸出結果中的 E 大寫。
下面的程式碼演示了小數的表示以及輸出:
- int main()
- {
- float a = 0.302;
- float b = 128.101;
- double c = 123;
- float d = 112.64E3;
- double e = 0.7623e-2;
- float f = 1.23002398;
- printf("a=%e \nb=%f \nc=%lf \nd=%lE \ne=%lf \nf=%f\n", a, b, c, d, e, f);
- return 0;
- }
執行結果:
a=3.020000e-01b=128.100998
c=123.000000
d=1.126400E+05
e=0.007623
f=1.230024
對程式碼的說明:
1) %f 和 %lf 預設保留六位小數,不足六位以 0 補齊,超過六位按四捨五入截斷。
2) 將整數賦值給 float 變數時會變成小數。
3) 以指數形式輸出小數時,輸出結果為科學計數法;也就是說,尾數部分的取值為:0 ≤ 尾數 < 10。
4) b 的輸出結果讓人費解,才三位小數,為什麼不能精確輸出,而是輸出一個近似值呢?這和小數在記憶體中的儲存形式有關,很多簡單的小數壓根不能精確儲存,所以也就不能精確輸出,我們將在下節《小數在記憶體中是如何儲存的,揭祕諾貝爾獎級別的設計(長篇神文)》中詳細講解。
另外,小數還有一種更加智慧的輸出方式,就是使用%g。%g 會對比小數的十進位制形式和指數形式,以最短的方式來輸出小數,讓輸出結果更加簡練。所謂最短,就是輸出結果佔用最少的字元。
%g 使用示例:
- int main()
- {
- float a = 0.00001;
- float b = 30000000;
- float c = 12.84;
- float d = 1.229338455;
- printf("a=%g \nb=%g \nc=%g \nd=%g\n", a, b, c, d);
- return 0;
- }
執行結果:
a=1e-05b=3e+07
c=12.84
d=1.22934
對各個小數的分析:
- a 的十進位制形式是 0.00001,佔用七個字元的位置,a 的指數形式是 1e-05,佔用五個字元的位置,指數形式較短,所以以指數的形式輸出。
- b 的十進位制形式是 30000000,佔用八個字元的位置,b 的指數形式是 3e+07,佔用五個字元的位置,指數形式較短,所以以指數的形式輸出。
- c 的十進位制形式是 12.84,佔用五個字元的位置,c 的指數形式是 1.284e+01,佔用九個字元的位置,十進位制形式較短,所以以十進位制的形式輸出。
- d 的十進位制形式是 1.22934,佔用七個字元的位置,d 的指數形式是 1.22934e+00,佔用十一個字元的位置,十進位制形式較短,所以以十進位制的形式輸出。
讀者需要注意的兩點是:
- %g 預設最多保留六位有效數字,包括整數部分和小數部分;%f 和 %e 預設保留六位小數,只包括小數部分。
- %g 不會在最後強加 0 來湊夠有效數字的位數,而 %f 和 %e 會在最後強加 0 來湊夠小數部分的位數。
總之,%g 要以最短的方式來輸出小數,並且小數部分表現很自然,不會強加零,比 %f 和 %e 更有彈性,這在大部分情況下是符合使用者習慣的。
除了 %g,還有 %lg、%G、%lG:
- %g 和 %lg 分別用來輸出 float 型別和 double 型別,並且當以指數形式輸出時,e小寫。
- %G 和 %lG 也分別用來輸出 float 型別和 double 型別,只是當以指數形式輸出時,E大寫。
數字的字尾
一個數字,是有預設型別的:對於整數,預設是 int 型別;對於小數,預設是 double 型別。
請看下面的例子:
- long a = 100;
- int b = 294;
- float x = 52.55;
- float y = 18.6;
100 和 294 這兩個數字預設都是 int 型別的,將 100 賦值給 a,必須先從 int 型別轉換為 long 型別,而將 294 賦值給 b 就不用轉換了。
52.55 和 18.6 這兩個數字預設都是 double 型別的,將 52.55 賦值給 x,必須先從 double 型別轉換為 float 型別,而將 18.6 賦值給 y 就不用轉換了。
如果不想讓數字使用預設的型別,那麼可以給數字加上字尾,手動指明型別:
- 在整數後面緊跟 l 或者 L(不區分大小寫)表明該數字是 long 型別;
- 在小數後面緊跟 f 或者 F(不區分大小寫)表明該數字是 float 型別。
請看下面的程式碼:
- long a = 100l;
- int b = 294;
- short c = 32L;
- float x = 52.55f;
- double y = 18.6F;
- float z = 0.02;
加上字尾,雖然數字的型別變了,但這並不意味著該數字只能賦值給指定的型別,它仍然能夠賦值給其他的型別,只要進行了一下型別轉換就可以了。
對於初學者,很少會用到數字的字尾,加不加往往沒有什麼區別,也不影響實際程式設計,但是既然學了C語言,還是要知道這個知識點的,萬一看到別人的程式碼這麼用了,而你卻不明白怎麼回事,那就尷尬了。
關於資料型別的轉換,我們將在《C語言資料型別轉換》一節中深入探討。
小數和整數相互賦值
在C語言中,整數和小數之間可以相互賦值:
- 將一個整數賦值給小數型別,在小數點後面加 0 就可以,加幾個都無所謂。
- 將一個小數賦值給整數型別,就得把小數部分丟掉,只能取整數部分,這會改變數字本來的值。注意是直接丟掉小數部分,而不是按照四捨五入取近似值。
請看下面的程式碼:
- int main(){
- float f = 251;
- int w = 19.427;
- int x = 92.78;
- int y = 0.52;
- int z = -87.27;
- printf("f = %f, w = %d, x = %d, y = %d, z = %d\n", f, w, x, y, z);
- return 0;
- }
執行結果:f = 251.000000, w = 19, x = 92, y = 0, z = -87
由於將小數賦值給整數型別時會“失真”,所以編譯器一般會給出警告,讓大家引起注意。