C語言浮點數

1、浮點數的概念

浮點數也稱小數或實數。例如,0.0、75.0、4.02三、0.2七、-937.198 都是合法的小數。程序員

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

在任何區間內(如1.0 到 2.0 之間)都存在無窮多個實數,計算機的浮點數不能表示區間內全部的值。函數

2、點用內存的狀況

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

示例(book71.c)測試

/*
 * 程序名:book71.c,此程序測試float、double和long double佔用內存的字節數
 * 做者:C語言技術網(www.freecplus.net) 日期:20190525
*/
#include <stdio.h>

int main()
{
  printf("sizeof float is %d\n",sizeof(float));
  printf("sizeof double is %d\n",sizeof(double));
  printf("sizeof long double is %d\n",sizeof(long double));
}

運行效果操作系統

在這裏插入圖片描述

3、浮點數的精度

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

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

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

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

一、測試float類型

示例(book73.c)

/*
 * 程序名:book73.c,此程序測試float的特徵
 * 做者:C語言技術網(www.freecplus.net) 日期:20190525
*/
#include <stdio.h> 

int main()
{
  float ff2=9.9;   // 測試2位的浮點數
  printf("ff2=%f\n",ff2);
  if (ff2==9.9) printf("ff2==9.9\n");

  float ff5=99.999;   // 測試5位的浮點數
  printf("ff5=%f\n",ff5);
  if (ff5==99.999) printf("ff5==99.999\n");

  float ff6=999.999;   // 測試6位的浮點數
  printf("ff6=%f\n",ff6);
  if (ff6==999.999) printf("ff6==999.999\n");

  float ff7=9999.999;   // 測試7位的浮點數
  printf("ff7=%f\n",ff7);
  if (ff7==9999.999) printf("ff7==9999.999\n");

  float ff8=99999.999;   // 測試8位的浮點數
  printf("ff8=%f\n",ff8);
  if (ff8==99999.999) printf("ff8==99999.999\n");
}

運行效果

在這裏插入圖片描述

從程序的運行咱們能夠看出float數的兩個特徵:

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

2)用「==」能夠比較兩個整數或字符是否相等,可是,看起來相等的兩個浮點數,就是不會相等。

二、測試double類型

示例(book74.c)

/*
 * 程序名:book74.c,此程序測試double的特徵
 * 做者:C語言技術網(www.freecplus.net) 日期:20190525
*/
#include <stdio.h> 

int main()
{
  double ff2=9.9;   // 測試2位的浮點數
  printf("ff2=%lf\n",ff2);
  if (ff2==9.9) printf("ff2與9.9相等。\n");

  double ff12=999999999.99;   // 測試12位的浮點數
  printf("ff12=%lf\n",ff12);
  if (ff12==999999999.99) printf("ff12與999999999.999相等。\n");

  double ff13=9999999999.99;   // 測試13位的浮點數
  printf("ff13=%lf\n",ff13);
  if (ff13==9999999999.99) printf("ff13與9999999999.999相等。\n");

  double ff14=99999999999.99;   // 測試14位的浮點數
  printf("ff14=%lf\n",ff14);
  if (ff14==99999999999.99) printf("ff14與99999999999.999相等。\n");

  double ff15=999999999999.99;   // 測試15位的浮點數
  printf("ff15=%lf\n",ff15);
  if (ff15==999999999999.99) printf("ff15與999999999999.999相等。\n");

  double ff16=9999999999999.99;   // 測試16位的浮點數
  printf("ff16=%lf\n",ff16);
  if (ff16==9999999999999.99) printf("ff16與9999999999999.999相等。\n");

  double ff17=99999999999999.99;   // 測試17位的浮點數
  printf("ff17=%lf\n",ff17);
  if (ff17==99999999999999.99) printf("ff17與99999999999999.999相等。\n");

  double ff18=999999999999999.99;   // 測試17位的浮點數
  printf("ff18=%lf\n",ff18);
  if (ff18==999999999999999.99) printf("ff17與99999999999999.999相等。\n");
}

運行效果

在這裏插入圖片描述

從程序的運行咱們能夠看出double數的兩個特徵:

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

2)用「==」能夠比較兩個double數值是否相等。

三、測試long double類型

示例(book75.c)

/*
 * 程序名:book75.c,此程序測試long double的特徵
 * 做者:C語言技術網(www.freecplus.net) 日期:20190525
*/
#include <stdio.h> 

int main()
{
  long double ff2=9.9;   // 測試2位的浮點數
  printf("ff2=%Lf\n",ff2);
  if (ff2==9.9) printf("ff2與9.9相等。\n");

  long double ff12=999999999.99;   // 測試12位的浮點數
  printf("ff12=%Lf\n",ff12);
  if (ff12==999999999.99) printf("ff12與999999999.999相等。\n");

  long double ff13=9999999999.99;   // 測試13位的浮點數
  printf("ff13=%Lf\n",ff13);
  if (ff13==9999999999.99) printf("ff13與9999999999.999相等。\n");

  long double ff14=99999999999.99;   // 測試14位的浮點數
  printf("ff14=%Lf\n",ff14);
  if (ff14==99999999999.99) printf("ff14與99999999999.999相等。\n");

  long double ff15=999999999999.99;   // 測試15位的浮點數
  printf("ff15=%Lf\n",ff15);
  if (ff15==999999999999.99) printf("ff15與999999999999.999相等。\n");

  long double ff16=9999999999999.99;   // 測試16位的浮點數
  printf("ff16=%Lf\n",ff16);
  if (ff16==9999999999999.99) printf("ff16與9999999999999.999相等。\n");

  long double ff17=99999999999999.99;   // 測試17位的浮點數
  printf("ff17=%Lf\n",ff17);
  if (ff17==99999999999999.99) printf("ff17與99999999999999.999相等。\n");

  long double ff18=999999999999999.99;   // 測試17位的浮點數
  printf("ff18=%Lf\n",ff18);
  if (ff18==999999999999999.99) printf("ff17與99999999999999.999相等。\n");
}

運行效果

在這裏插入圖片描述

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

四、測試總結

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

double能表達15-16位有效的數字,能夠用「==」判斷兩個數字是否相等。

long double佔用的內存是double的兩倍,但表達數據的精度和double相同。

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

4、浮點數的輸出

float採用%f佔位符。

double採用%lf佔位符。測試結果證實,double不能夠用%f輸入,但能夠用%f輸出,可是不建議採用%f,由於不一樣的編譯器可能會有差異。

long double採用%Lf佔位符,注意,L是大寫。

浮點數輸出缺省顯示小數點後六位。

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

double ff=70001.538;
printf("ff=%lf=\n",ff);       // 輸出結果是ff=70001.538000=
printf("ff=%.4lf=\n",ff);     // 輸出結果是ff=70001.5380=
printf("ff=%11.4lf=\n",ff);   // 輸出結果是ff= 70001.5380=
printf("ff=%8.4lf=\n",ff);    // 輸出結果是ff=70001.5380=

5、經常使用的庫函數

在接下來的內容中,我只介紹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整除後的雙精度餘數
// 把雙精度val分解成整數部分和小數部分,整數部分存放在ip所指的變量中,返回小數部分。
double modf(double val,double *ip);

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

6、整數轉換爲浮點數

示例(book77.c)

/*
 * 程序名:book77.c,此程序測試整數與浮點數的轉換。
 * 做者:C語言技術網(www.freecplus.net) 日期:20190525
*/
#include <stdio.h>

int main()
{
  int ii=3;
  int jj=4;
  double dd;

  dd=ii;        // 能夠
  printf("dd is %.2lf\n",dd);

  dd=ii/jj;     // 不行
  printf("dd is %.2lf\n",dd);

  dd=(double)ii/jj;  // 能夠
  printf("dd is %.2lf\n",dd);
}

運行效果

在這裏插入圖片描述

須要特別注意的是dd=ii/jj這一行代碼,dd的值0,不是0.75,有點意外,因此,若是對整數轉換爲浮點數沒有把握,加(double)強制轉換是個好辦法。關於數據類型的轉換,在《C語言數據類型轉換》章節中將有更詳細的介紹。

7、應用經驗

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

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

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

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

碼農之道:高水平的程序員不容易掉坑裏,注意,是不容易,不是不會,最好的方法是不要靠近坑。

8、科學計數法

在實際開發中,咱們不多使用科學計數法,可是它常常出如今計算機系統中,例如浮點數在內存中的存放方式就是科學計數法,因此咱們仍是有必要學習科學計數法。

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

例如:51400000000=5.14×10^11^,計算機表達10的冪是通常是用E或e,也就是51400000000=5.14E11或5.14e11。

用科學記數法表示數時,不改變數的符號,只是改變數的書寫形式而已,能夠方便的表示平常生活中遇到的一些極大或極小的數 。如:光的速度大約是300,000,000米/秒;全世界人口數大約是:6,100,000,000,這樣的數書寫和顯示都很不方便,爲了免去寫這麼多重複的0,將其表現爲這樣的形式:6,100,000,000=6.1×10^9^,即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)

/*
 * 程序名:book78.c,此程序測試浮點數據的科學計數法。
 * 做者:C語言技術網(www.freecplus.net) 日期:20190525
*/
#include <stdio.h>

int main()
{
  double dd;

  dd=123000000;
  printf("dd is  %.2e\n",dd);

  dd=-123000000;
  printf("dd is %.2e\n",dd);

  dd=0.0000000123;
  printf("dd is  %.2e\n",dd);

  dd=-0.0000000123;
  printf("dd is %.2e\n",dd);
}

運行效果

在這裏插入圖片描述

9、課後做業

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

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

3)關於浮點數在內存中的存儲方式,建議你們去百度一下(搜索關鍵字爲C語言浮點數存儲方式),瞭解一下相關的概念。

4)編寫示例程序,測試把浮點數賦給整數變量的結果,並思考緣由。

5)本題做業建議在學完《C語言數據類型轉換》後再作,由於有知識點交叉,重寫浮點數的經常使用庫函數,實現其功能,函數的聲明以下:

double FABS(const double x);          // 求雙精度實數x的絕對值
double ROUND(const double x);         // double四捨五入
double CEIL(const double x);          // double向上取整數
double FLOOR(const double x);         // double向下取整數
// 把雙精度val分解成整數部分和小數部分,整數部分存放在ip所指的變量中,返回小數部分。
double MODF(double val,double *ip);

10、版權聲明

C語言技術網原創文章,轉載請說明文章的來源、做者和原文的連接。
來源:C語言技術網(www.freecplus.net)
做者:碼農有道

若是這篇文章對您有幫助,請點贊支持,或在您的博客中轉發個人文章,謝謝!!!若是文章有錯別字,或者內容有錯誤,或其餘的建議和意見,請您留言指正,很是感謝!!!

相關文章
相關標籤/搜索