C語言浮點數

 

浮點數的概念

       浮點數也稱小數或實數。例如,0.0、75.0、4.023、0.27、-937.198 都是合法的小數。這是常見的小數的表現形式,稱爲十進制形式。

       C語言中採用float和double關鍵字來定義小數,float稱爲單精度浮點型,double稱爲雙精度浮點型,long double更長的雙精度浮點型。

       在任何區間內(如1.0 到 2.0 之間)都存在無窮多個實數,計算機的浮點數不能表示區間內所有的值。浮點數通常只是實際值的近似值,例如7.0可能被儲存爲浮點值6.99999。

點用內存的情況

       我們先來測試一下float、double和long double三種浮點數據類型佔用內存的字節數。

       示例(book71.c)

       

       運行結果

       

浮點數的精度

       C標準規定,float類型必須至少能表示6位有效數字,且取值範圍至少是10-37~10+37。

       double類型和 float類型的最小取值範圍相同,但至少必須能表示10位有效數字。

       long double,以滿足比double類型更高的精度要求。不過,C只保證long double類型至少與double類型的精度相同。

       看了上面這段文字,估計大家有點暈,在之前的整數章節中,long比int的佔用的內存多,存放數據的值也就越大,並且有一個準確的範圍,但是,爲什麼各種浮點數存放數據的值怎麼就這麼模糊呢?我先不解釋原因,浮點數的存儲方式比較複雜,暫時不討論,先用幾個程序來測試一下它們的特徵。

1、測試float類型

       示例(book73.c)

       

       運行結果

       

       從程序的運行我們可以看出float數的兩個特徵:

       1)float數據類型表達的是一個近似的數,不是準確的,小數點後的n位有誤差,浮點數的位數越大,誤差越大,到8位的時候,誤差了1,基本上不能用了。

       2)用“==”可以比較兩個整數或字符是否相等,但是,看起來相等的兩個浮點數,就是不會相等。

2、測試double類型

       示例(book74.c)

       

       運行結果

       

       從程序的運行我們可以看出double數的兩個特徵:

       1)double數據類型表達的也是一個近似的數,不是準確的,小數點後的n位有誤差,浮點數的位數越大,誤差越大,到17位的時候,誤差了1,基本上不能用了。

       2)用“==”可以比較兩個double數值是否相等。

3、測試long double類型

       示例(book75.c)

       

       運行結果

       

       long double的測試結果與double相同。

4、測試總結

      float只能表達6-7位的有效數字,不能用“==”判斷兩個數字是否相等。

      double能表達15-16位有效的數字,可以用“==”判斷兩個數字是否相等。

      long double和double的特徵相同。

      在實際開發中,建議棄用float,只採用double就可以,long double暫時沒有必要,但不知道以後的操作系統和編譯器對long double是否有改進。

浮點數的輸出

      float採用%f輸出,double採用%lf輸出,測試結果證明,double也可以採用%f輸出。

      long double採用%Lf輸出,注意,L是大寫。

      %lf缺省顯示小數點後六位。

      如果要顯示小數點後n位,用%.nlf,例如:

      double ff=7.5;

      %.2lf  顯示 7.50

      浮點數採用%lf輸出,完整的輸出格式是%m.nlf,指定輸出數據整數部分和小數部分共佔m位,其中有n位是小數。如果數值長度小於m,則左端補空格,若數值長度大於m,則按實際位數輸出。

常用的庫函數

      在接下來的內容中,我只介紹double,不再介紹float和long double兩種數據類型相關的知識。

      以下是常用的浮點數函數,必須掌握。

      double atof(const char *nptr);       // 把字符串nptr轉換爲double

      double fabs(double x);               // 求雙精度實數x的絕對值

      double pow(double x, double y);     // 求 x 的 y 次冪(次方)

      double round(double x);              // double四捨五入

      double ceil(double x);                 // double向上取整數

      double floor(double x);               // double向下取整數

      double fmod(double x,double y);     // 求x/y整除後的雙精度餘數

      double modf(double val,double *ip); // 把雙精度val分解成整數部分和小數部分,整數部分存放在ip所指的變量中,返回小數部分。

      還有一些數據計算函數,如正弦、對數、指數等,實際開發中極少使用,大家要用的時候再查資料,我就不介紹了。

整數轉換爲浮點數

      我們先來看一個示例(book77.c):

       

      運行結果

       

      需要特別注意的是dd=ii/jj這一行代碼,dd的值0,不是0.75,有點意外,所以,如果對整數轉換爲浮點數沒有把握,加(double)強制轉換是個好辦法。

應用技巧

      浮點數有一些坑,例如兩個浮點數不相等和精度的問題,在實際開發中,我們經常用整數代替浮點數,因爲整數是精確的,效率也更高。

      例如人的身高一米七五,以米爲單位,用浮點數表示是1.75米,如果以釐米爲單位,用整數表示是175。

      long整數的取值是-9223372036854775808~9223372036854775807,有效數字是19位,而double的有效數字才15-16位,所以,整數可以表達的小數更大的數,更實用,麻煩也更少。

      貨幣:1.75元,如果採用0.01元爲單位就是175,採用0.001元爲單位就是1750,如果你說要更多小數怎麼辦?你這是鑽牛角尖。

      給大家說一個道,高水平的程序員不容易掉坑裏,注意,是不容易,不是一定不會,最好的方法是沒有坑。

科學計數法

      在實際開發中,我們很少使用科學計數法,但是它經常出現在計算機系統中,例如浮點數在內存中的存放方式就是科學計數法,所以我們還是有必要學習科學計數法。

      科學記數法是一種記數的方法。把一個數表示成a與10的n次冪相乘的形式(1≤|a|<10,n爲整數),這種記數法叫做科學記數法。當我們要書寫或運算某個較大或較小且位數較多時,用科學記數法免去浪費很多空間和時間。

      例如:51400000000=5.14×1011。計算器或電腦表達10的冪是一般是用E或e,也就是51400000000=5.14E11或5.14e11。

      用科學記數法表示數時,不改變數的符號,只是改變數的書寫形式而已,可以方便的表示日常生活中遇到的一些極大或極小的數 。如:光的速度大約是300,000,000米/秒;全世界人口數大約是:6,100,000,000。

      這樣的數,書寫和顯示都很不方便,我們可以免去寫這麼多重複的0,將其表現爲這樣的形式:6,100,000,000=6.1×109,即6.1E9或6.1e9。

      或:0.00001=1×10-5,即絕對值小於1的數也可以用科學記數法表示爲a乘10 的負n次方的形式。即1E-5或1e-5。

      科學計數法採用%e或%E輸出,完整的輸出格式是%m.ne或%m.nE,指定輸出數據整數部分和小數部分共佔m位,其中有n位是小數。如果數值長度小於m,則左端補空格,若數值長度大於m,則按實際位數輸出。

      示例(book78.c):

       

      運行結果

       

 

課後作業

1、編寫示例程序,類似本章節的book71.c、book73.c、book74.c、book75.c、book77.c、book78.c,編譯並運行它,記住,程序員是寫出來的,不是看出來的,熟能生巧,你每天的付出都有意義。

2、編寫示例程序,測試浮點數賦值超過取值範圍的後果。

3、重寫浮點數的常用庫函數,實現其功能,函數的聲明如下:

      以下作業建議在學完《數據類型轉換》後再做,因爲有知識點交叉。

      double FABS(const double x);            // 求雙精度實數x的絕對值

      double ROUND(const double x);         // double四捨五入

      double CEIL(const double x);             // double向上取整數

      double FLOOR(const double x);          // double向下取整數

      double MODF(double val,double *ip);    // 把雙精度val分解成整數部分和小數部分,整數部分存放在ip所指的變量中,返回小數部分。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章