一起學習C語言:C語言數據類型(三)

  上一篇<一起學習C語言:C語言數據類型(二)>中,我們瞭解了整形和字符類型的定義,以及二進制到八進制、十進制和十六進制轉換方式。本篇文章中,我們進行分析浮點數的運算,並通過二進制、十進制和十六進制表達浮點數值。


章節預覽:

1.4 浮點數類型
1.4.1 浮點數的表示方法
1.4.2 單精度浮點數類型
1.4.3 關於浮點數精度問題
1.4.4 實數轉換到單精度浮點數
1.4.5 單精度浮點數取值範圍
1.4.6 雙精度浮點數類型
1.4.7 雙精度浮點數取值範圍
1.5 本章總結
1.6 練習題
目錄預覽


章節內容:


1.4 浮點數類型


  浮點數類型採用實數形式展示,它由符號位、指數位和尾數位構成,因此,不能直接按照二進制數字方式計算。另外,浮點數類型在編譯器中只以有符號類型形式存在,下面我們來分析它的組成結構和運算方式。


1.4.1 浮點數的表示方法

  在IEEE-754標準中,浮點數的定義如下:
    把一個數的有效數字和數的範圍在計算機的一個存儲單元中分別予以表示,數的小數點位置隨比例因子的不同而在一定範圍內自由浮動。
    一個R進制數N使用科學表達式表示爲N = R^e * M(或M * R^e),其中R表示基數、M表示尾數、e表示指數。


1.4.2 單精度浮點數類型

  float 表示單精度浮點數類型,在16位、32位以及64位系統下都佔用四個字節(Byte)。參考圖1.4-1 單精度浮點數結構表,我們來分析實數的計算方式:


bit(位) 31bit (23-30)bit (0-22)bit
數據描述 符號域 指數域 尾數域
1.4-1 單精度浮點數結構表

尾數域:

  數據範圍0—22bit,共23位(bit),用來表示實數轉換爲二進制數字的部分,當轉換後的二進制數字不足23位時,採用低位補0對齊。下面舉個例子,實數5.25:
    整數部分 :直接採用二進制轉換得到 101;
    小數部分 :採用“乘2取整”運算,如果結果大於等於1取二進制數字1,否則取二進制數字0,然後用得到的結果小數部分繼續運算,一直到小數部分爲0或尾數域足夠23位:
    0.25 * 2 = 0.5,取0;
    0.5 * 2 = 1,取1;
    小數部分得到 01,整數和小數部分組合爲 101.01;

    二進制科學表達式 :規範要求浮點數的小數點左側必須爲1,我們採用小數點左移得到1.0101,這個示例中我們左移了兩位,表示爲 1.0101 * 2^2;

    尾數域完整數據 :尾數數據儲存時,應省略小數點前面的1,這麼做是爲了省出一位二進制數字,用來存儲更多的數據,按左高位右低位表示爲 010 1000 0000 0000 0000。


指數域:

  指數域由8位介碼(E)採用移碼方式來表示正負指數,數據範圍23—30bit,共8位(bit),介碼有效範圍爲1—254,偏移量爲127,介碼(E) = 127 + 元數據⑵。示例中,指數域計算方式:
  實數5.25計算尾數域時,小數點左移了兩位,所以我們的元數據爲2,然後通過127 + 2 得到介碼129,二進制數字表示爲 1000 0001。


(2) :指數(e)的最高位爲符號位,其餘位爲數據位,可表達有效範圍爲-126—127,指數(e) = 介碼(E) – 127。


符號域:

  數據爲31bit,佔1位(bit),0表示正數,1表示負數。


bit(位) 31bit (23-30)bit (0-22)bit
實數5.25 0 1000 0001 010 1000 0000 0000 0000 0000
1.4-2 實數5.25組成部分

  參考圖3.4-2 實數5.25組成部分,我們得到二進制數字 0100 0000 1010 1000 0000 0000 0000 0000,十六進制 0x40A8000‬。


1.4.3 關於浮點數精度問題

  浮點數爲什麼用精度標記?原因很簡單,浮點數尾數域有限,比如單精度浮點數,只能存儲23位二進制數字,多餘的部分會被拋棄,關於這個問題,我們還是用例子的形式表示,參考實數5.168:
    整數部分 :101;
    小數部分 :0010101100000010011110101110110011001100…

    這個示例中,小數部分從1100開始無限循環,內存中只存儲這個二進制數字的前23位,得到的只是這個數字的接近值,這屬於由精度問題產生的其中一種情況。
    在編譯器中使用float 類型儲存5.168時,得到實際數據爲5.1680002,在實際使用時,如果必須用到更高精度的浮點數,可以使用雙精度浮點數類型。


1.4.4 實數轉換到單精度浮點數

  當我們得到一串數字,比如十六進制C14A0000,我們可以先把這串數字轉換爲二進制數字然後放到相應區域進行計算:
  轉換爲二進制數字:


bit(位) (28-31)bit (24-27)bit (20-23)bit (16-19)bit (12-15)bit (8-11)bit (4-7)bit (0-3)bit
十六進制數字 C 1 4 A 0 0 0 0
二進制數字 1100 0001 0100 1010 0000 0000 0000 0000
1.4-2 實數C14A0000

  參考圖1.4-2 實數C14A0000,轉換到二進制數字爲 1100 0001 0100 1010 0000 0000 0000 0000,然後數據放入相應區域:

bit(位) 31bit (23-30)bit (0-22)bit
實數 C14A0000 1 1000 0010 100 1010 0000 0000 0000
數據描述 符號域 指數域 尾數域
1.4-3 實數C14A0000組成部分

  尾數域 :100 1010 0000 0000 0000 0000;
  指數域 :1000 0010;
  符號域 :1;


首先計算指數域:

  指數e = 1000 0010 – 0111 1111 = 0000 0011,轉換到十進制數字爲3。


然後計算尾數域:

  首先把最低位爲1之後的0去掉得到 100 101,二進制科學表示方式爲 1.100 101 * 2^3,實數N等於:
    N = (1 * 2^0 + 1 * 2^-1 + 1 * 2^-4 + 1 * 2^-6) * 2^3
    N = (1 + 0.5 + 0.0625 + 0.015625) * 8
    N = 12.625


最後計算符號域:

  符號位爲1,表示這個數爲負數,十進制數字爲 -12.625。


1.4.5 單精度浮點數取值範圍

  之前介紹浮點數存儲的數字與部分實際數字有些偏差,在取值範圍這部分也存在着偏差,浮點數範圍主要由指數域決定的,比如單精度浮點數:正數指數值最大有效值是127,可以得到正數最大理論值1.111 1111 1111 1111 1111 1111 * 2^127,接近2 * 2^127,VS2010編譯器中爲3.402823466e+38F;負數指數最小有效值是-126,可以得到正數最小理論值1.111 1111 1111 1111 1111 1111 * 2^-126,接近2 * 2^-126,VS2010編譯器中爲1.175494351e-38F。負數最大、最小理論值與正數剛好相反,當數據接近-2 * 2^127時,爲負數最小值,數據接近-2 * 2^-126時,爲負數最大值。在大部分編譯器中,單精度浮點數可以表示包含小數在內的6-8位十進制數字。


1.4.6 雙精度浮點數類型

  在部分領域中,需要使用高精度的數字,比如納秒與秒級單位之間的轉換使用單精度浮點數無法顯示完整的十進制數,這種情況下,應使用雙精度浮點類型存儲。double 表示雙精度浮點數類型, 在16位、32位以及64位系統下都佔用八個字節(Byte)。參考圖1.4-4 雙精度浮點數結構表,我們來分析實數的運算方式:


bit(位) 63bit (52-62)bit (0-51)bit
數據描述 符號域 指數域 尾數域
1.4-4 雙精度浮點數結構表

尾數域:

  數據範圍0—51bit,共52位(bit),用來表示實數轉換爲二進制數字的部分,當轉換後的二進制數字不夠52位時,採用低位補0對齊。下面舉個例子,實數5.25000012345:
    整數部分:直接採用二進制轉換得到 101;
    小數部分:還是採用“乘2取整”運算,如果結果大於等於1取二進制數字1,否則取二進制數字0,然後用得到的結果小數部分繼續運算,一直到小數部分爲0或尾數域足夠52位:

      0.25000012345 * 2 = 0.5000002469‬,取0;
      0.5000002469‬ * 2 = 1.0000004938,取1;
      0.0000004938 * 2 = 0.0000009876,取0;
      ……

      得到小數部分0100 0000 0000 0000 0000 0010 0001 0010 0011 0110 1011 0101 1101 1111 1111 1011 … ,整數和小數部分組合爲 101.01 0000 0000 0000 0000 0000 1000 0100 1000 1101 1010 1101 0111… ;

    尾數域完整數據:首先整數部分二進制數字01放入尾數域,然後把小數部分前50位二進制數字放入尾數域,得到
0101 0000 0000 0000 0000 0000 1000 0100 1000 1101 1010 1101 0111,一共52位有效二進制數字。

    優化整數和小數部分組合:101.01 0000 0000 0000 0000 0000 1000 0100 1000 1101 1010 1101 0111,一共53位二進制數字。

    二進制科學表示方式: 1.0101 0000 0000 0000 0000 0000 1000 0100 1000 1101 1010 1101 0111 * 2^2;


指數域:

  數據範圍52—62bit,共11位(bit),介碼有效範圍爲1—2046,指數有效範圍爲-1022—1023。示例中,介碼(M) = 1023 + 2 = 1025,二進制數字表示爲 100 0000 0001‬。


符號域:

  數據爲63bit,佔1位(bit),0表示正數,1表示負數。


bit(位) 63bit (52-62)bit (0-51)bit
實數 5.25000012345 0 100 0000 0001 0101 0000 0000 0000 0000 0000 1000 0100 1000 1101 1010 1101 0111
1.4-5 實數5.25000012345組成部分

  參考圖1.4-5 實數5.25000012345組成部分,我們得到二進制數字0100 0000 0001 0101 0000 0000 0000 0000 0000 1000 0100 1000 1101 1010 1101 0111,十六進制 0x4015 0000 0848 DAD7‬‬。


1.4.7 雙精度浮點數取值範圍

  雙精度浮點數由於擁有更多的存儲空間,較於單精度浮點數而言,可以提供更精準的數據信息,雙精度浮點數正數指數最大有效值是1023,得到正數最大值接近2 * 2^1023,VS2010編譯器中爲1.7976931348623158e+308;負數指數最小有效值是-1022,可以得到正數最小值接近2 * 2^-1022,VS2010編譯器中爲2.2250738585072014e-308。負數最大值接近 -2 * 2^-1022,負數最小值接近 -2 * 2^1023;在大部分編譯器中,雙精度浮點數可以表示包含小數在內的16-17位十進制數字。


1.5 本章總結

  本章節,我們瞭解了C語言的基本類型和不同的類型運算方式,日常編程中,我需要做到正確選擇類型、正確使用類型,這樣可以避免數據存儲造成的信息錯誤、程序異常崩潰等問題。本章節內容稍微有些複雜,需要多次學習才能完全理解,初期做到類型可以靈活使用就好,中後期再來回顧本章節,應該會有新的發現。


1.6 練習題

  1. 無符號短整型與有符號短整型有哪些區別?
  2. 使用十進制數字4096轉換到二進制、八進制和十六進制。
  3. 參考Ascll碼錶,輸出換行、空格和字符’A’。
  4. 短整型、整形和長整形分別佔用幾個字節?數字123456789使用哪個類型保存比較適合?
  5. 實數12.625轉換到十六進制。
  6. 實數0xC0C8 1CA8 0000 0000轉換到十進制。

目錄預覽


<一起學習C語言:C語言發展歷程以及定製學習計劃>
<一起學習C語言:初步進入編程世界(一)>
<一起學習C語言:初步進入編程世界(二)>
<一起學習C語言:初步進入編程世界(三)>
<一起學習C語言:C語言數據類型(一)>
<一起學習C語言:C語言數據類型(二)>

發佈了97 篇原創文章 · 獲贊 218 · 訪問量 19萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章