1. 程式人生 > >深入理解計算機系統之整型與浮點型

深入理解計算機系統之整型與浮點型

在計算機儲存系統裡面,算術型別可以分為兩類:整型(intergral type,包括字元和布林型別在內)和浮點型。在看簡單地看了深入理解計算機系統的第二章後,有了稍微深刻但是有非常淺顯的理解,然後又看了阮師兄的一篇博文,所以做了一點筆記。

下面先來看一個例子程式:

#include <stdio.h>
  void main(void){
    int num=9; /* num是整型變數,設為9 */
    float* pFloat=&num; /* pFloat表示num的記憶體地址,但是設為浮點數 */
    printf("num的值為:%d\n",num); /* 顯示num的整型值 */
    printf("*pFloat的值為:%f\n",*pFloat); /* 顯示num的浮點值 */
    *pFloat=9.0; /* 將num的值改為浮點數 */
    printf("num的值為:%d\n",num); /* 顯示num的整型值 */
    printf("*pFloat的值為:%f\n",*pFloat); /* 顯示num的浮點值 */
  }

執行結果如下:

num的值為:9
*pFloat的值為:0.000000
num的值為:1091567616
*pFloat的值為:9.000000

這個例子是一個吧整數數值換成浮點形式的經典例子,理解了這個例子,可以讓我們對整型和浮點型的儲存方式都有一個更深刻的理解。

在討論浮點數之前,先看一下整數在計算機內部是怎樣表示的:

int num=9;

上面這條命令,聲明瞭一個整數變數,型別為int(預設為signed,有符號的),值為9(二進位制寫法為1001)。在普通的用4個位元組表示int變數。所以9就被儲存為00000000 00000000 00000000 00001001。如果要儲存一個有符號的整型,我們一般採用補碼編碼的形式。在這個定義中,將字的最高有效位解釋為負權, 最高有效位也成為符號位。也就是說,如果符號位是0,則這是一個非負數(包括0),如果符號位是1,則這是一個負數。

3.直到20世紀80年代,每個計算機制造商都設計了自己的表示浮點數的規則,但這是對應用程式可移植性的巨大挑戰,所以制定了國際標準IEEE 754,任意一個二進位制浮點數V可以表示成下面的形式:

#V=(1)SM2E(-1)^S*M*2^E
(1)(-1)^s表示符號位(術語:符號),當s=0,V為正數;當s=1,V為負數。
(2)M(位數)表示有效數字,大於等於1,小於2。
(3)2^E表示指數位,E叫階碼

舉例來說,十進位制的5.0,寫成二進位制是101.0,相當於1.01×2^2。那麼,按照上面V的格式,可以得出s=0,M=1.01,E=2。

十進位制的-5.0,寫成二進位制是-101.0,相當於-1.01×2^2。那麼,s=1,M=1.01,E=2。

IEEE 754規定,對於32位的浮點數,最高的1位是符號位s,接著的8位是指數E,剩下的23位為有效數字M:

這裡寫圖片描述

對於64位的浮點數,最高的1位是符號位S,接著的11位是指數E,剩下的52位為有效數字M:

這裡寫圖片描述

IEEE 754對有效數字M和指數E,還有一些特別規定。
前面說過,1≤M<2,也就是說,M可以寫成1.xxxxxx的形式,其中xxxxxx表示小數部分。IEEE 754規定,在計算機內部儲存M時,預設這個數的第一位總是1,因此可以被捨去,只儲存後面的xxxxxx部分。比如儲存1.01的時候,只儲存01,等到讀取的時候,再把第一位的1加上去。這樣做的目的,是節省1位有效數字。以32位浮點數為例,留給M只有23位,將第一位的1捨去以後,等於可以儲存24位有效數字。
至於指數E,情況就比較複雜。
首先,E為一個無符號整數(unsigned int)。這意味著,如果E為8位,它的取值範圍為0255;如果E為11位,它的取值範圍為02047。但是,我們知道,科學計數法中的E是可以出現負數的,所以IEEE 754規定,E的真實值必須再減去一箇中間數(偏置),才會得到我們科學計數法中的E。對於8位的E,這個中間數是127;對於11位的E,這個中間數是1023。
比如,2^10的E是10,所以儲存成32位浮點數時,必須儲存成10+127=137,即10001001。
然後,指數E還可以再分成三種情況:
(1)E不全為0或不全為1。這時,浮點數就採用上面的規則表示,即指數E的計算值減去127(或1023),得到真實值,再將有效數字M前加上第一位的1。
(2)E全為0。這時,浮點數的指數E等於1-127(或者1-1023),有效數字M不再加上第一位的1,而是還原為0.xxxxxx的小數。這樣做是為了表示±0,以及接近於0的很小的數字。
(3)E全為1。這時,如果有效數字M全為0,表示±無窮大(正負取決於符號位s);如果有效數字M不全為0,表示這個數不是一個數(NaN)。

好了,關於浮點數的表示規則,就說到這裡。
下面,讓我們回到一開始的問題:
首先,將0x00000009拆分,得到第一位符號位s=0,後面8位的指數E=00000000,最後23位的有效數字M=000 0000 0000 0000 0000 1001。
由於指數E全為0,所以符合上一節的第二種情況。因此,浮點數V就寫成:
  V=(-1)0×0.00000000000000000001001×2(-126)=1.001×2^(-146)
顯然,V是一個很小的接近於0的正數,所以用十進位制小數表示就是0.000000。

再看例題的第二部分:
請問浮點數9.0,如何用二進位制表示?還原成十進位制又是多少?
首先,浮點數9.0等於二進位制的1001.0,即1.001×2^3。
那麼,第一位的符號位s=0,有效數字M等於001後面再加20個0,湊滿23位,指數E等於3+127=130,即10000010。
所以,寫成二進位制形式,應該是s+E+M,即0 10000010 001 0000 0000 0000 0000 0000。這個32位的二進位制數,還原成十進位制,正是1091567616。

在理解了單精度和雙精度制度之後,我又產生了一個疑問。 那就是c語言的printf輸出浮點數的一些問題,就是當printf列印*pFloat時為什麼會顯示小數點後六位,這裡貌似牽涉到計算機系統的堆疊問題,後面再慢慢梳理。

相關推薦

深入理解計算機系統

在計算機儲存系統裡面,算術型別可以分為兩類:整型(intergral type,包括字元和布林型別在內)和浮點型。在看簡單地看了深入理解計算機系統的第二章後,有了稍微深刻但是有非常淺顯的理解,然後又看了阮師兄的一篇博文,所以做了一點筆記。 下面先來看一個例子程

深入理解計算機系統 2.4.2 IEEE表示詳細講解

定義 IEEE浮點標準用以下公式表示\(V = (-1)^s * M * 2^E\) 符號(sign):s決定這書是負數(s = 1)還是正數(s = 0),而對於數值0的符號位解釋作為特殊情況處理 。 尾數(significand):M是一個二進位制小數,它的範圍是\

深入理解計算機系統虛擬存儲器

fragment 策略 動態鏈接 字段 索引 ~~ cti 錯誤 個數 http://blog.csdn.net/al_xin/article/details/38590931 進程提供給應用程序的關鍵抽象: 一個獨立的邏輯控制流,它提供一個假象,好像我們的程序獨占地

深入理解計算機系統--數值儲存(二)--C程式列印變數的每一位元組或者位

大端與小端 前面我們提到了依據CPU端模式的不同,資料的儲存順序也不一樣。 採用大小模式對資料進行存放的主要區別在於在存放的位元組順序,BE big-endian 大端模式 ,最直觀的位元組序 ,地址低位儲存值的高位,地址高位儲存值的低位 ,不需要考慮對

深入理解計算機系統--數值儲存(三)-- 原碼、反碼、補碼和移碼詳解

原碼 如果機器字長為n,那麼一個數的原碼就是用一個n位的二進位制數,其中最高位為符號位:正數為0,負數為1。剩下的n-1位表示概數的絕對值。 PS:正數的原、反、補碼都一樣:0的原碼跟反碼都有兩個,因為這裡0被分為+0和-0。 原碼就是符號位

深入理解計算機系統--記憶體定址(四)--linux中分段機制的實現方式

linux中的分段機制 前面說了那麼多關於分段機制的實現,其實,Linux以非常有限的方式使用分段。因為,Linux基本不使用分段的機制(注:並不是不使用,使用分段方式還是必須的,會簡化程式的編寫和執行方式),或者說,Linux中的分段機制只是為了相容IA

深入理解計算機系統--數值儲存(一)-CPU大端和小端模式詳解

大端與小端 在嵌入式開發中,大端(Big-endian)和小端(Little-endian)是一個很重要的概念。 MSB與LSB 最高有效位(MSB)指二進位制中最高值的位元。在16位元的數字音訊中,其第1個位元便對16bit的字的數值有最大的

深入理解計算機系統(2.8)---點數的舍入,Java中的舍入例子以及點數運算(重要)

https://www.cnblogs.com/zuoxiaolong/p/computer12.html 前言     上一章我們簡單介紹了IEEE浮點標準,本次我們主要講解一下浮點運算舍入的問題,以及簡單的介紹浮點數的運算。   之前我們已經提到過,有很多小數是二進位制

資料在計算機記憶體中的儲存

1、型別的歸類     整型家族:char、unsigned char、signed char      //對於char來說,標準裡並不預設其為有符號還是無符號的,這個結果取決於編譯器                         short ( signed shor

深入理解計算機系統(原書第三版)練習題2.6 感性認識型別(同一個數)在機器中表示

/** * 練習題2.6 感性認識整型和浮點型別(同一個數)在機器中表示 * 由於我的機器是小端表示,將列印結果還原真實數並用二進位制表示 * 41913500 -->(還原) 0x00359141 -->(二進位制) 0000 0000 0011 0101

深入理解計算機系統》Tiny服務器4——epoll類IO復用版Tiny

[] 用戶數據 nts tin 服務 監視 結束 col 結構   前幾篇博客分別講了基於多進程、select類型的IO復用、poll類型的IO復用以及多線程版本的Tiny服務器模型,並給出了主要的代碼。至於剩下的epoll類型的IO復用版,本來打算草草帶過,畢竟和其他兩種

深入理解計算機系統》讀書筆記(ch2)+ C 泛

tex byte 指向 get 讀書筆記 class its n) 支持 本章主要介紹各類型的機器表示,Stanford的CS107的lec2和lec3有精彩解釋,比看書快(當作書中只是的cache吧)。 lec4中介紹的C裏面如何使用泛型(沒有template, refe

深入理解計算機系統筆記第二章(一)

資訊的表示和處理(一) 大多數計算機使用8位的塊(也就是一個位元組byte),由此可以看到32位(4個位元組)系統和64位(8個位元組)系統的區別。32位系統在於cpu可以同時處理4個位元組(32位)的資料,那麼64位系統cpu可以同時處理8個位元組(64位)的資料。 一個

深入理解計算機系統 練習題2.25 答案分析

#include <stdio.h> #include "stdafx.h" #include <iostream> using namespace std; float sum_elements(float a[], unsi

深入理解計算機系統 練習題2.31 答案分析

測試程式碼 #include <stdio.h> #include "stdafx.h" #include <iostream> using namespace std; int uadd_ok(int x, int y) {

深入理解計算機系統(原書第三版)》pdf附網盤下載連結+(附一個菜鳥的java學習路)

技術書閱讀方法論 一.速讀一遍(最好在1~2天內完成) 人的大腦記憶力有限,在一天內快速看完一本書會在大腦裡留下深刻印象,對於之後複習以及總結都會有特別好的作用。 對於每一章的知識,先閱讀標題,弄懂大概講的是什麼主題,再去快速看一遍,不懂也沒有關係,但是一定要在不懂的

[深入理解計算機系統] 計算機如何實現乘法除法運算

乘法運算 (1)原碼一位乘法 演算法要點:(1)乘法通過加法和移位來實現。兩個5位二進位制數(最高位為符號位)相乘,共需要進行4次加法和4次移位。                  (2)部分積總是先

深入理解計算機系統淺析程式效能優化

此文已由作者餘笑天授權網易雲社群釋出。歡迎訪問網易雲社群,瞭解更多網易技術產品運營經驗。  本文主要是基於我之前學習《深入理解計算機系統》(以下簡稱CSAPP)這本書第五章優化程式效能內容的回顧以及總結。主要內容並沒有從大而全的方面去闡述如何優化程式,而是從一些細節著手來看待

深入理解計算機系統 練習題2.25-隱式強制類轉換導致的數組越界

print 代碼 nbsp end process 簡單 turned 轉換成 隱式 1 #include <stdio.h> 2 #include <iostream> 3 using namespace std; 4 5 flo

深入理解計算機系統家庭作業8.25題答案

#include "csapp.h" static sigjmp_buf env; //當呼叫sigsetjmp函式時將當前呼叫環境儲存在緩衝區env中,以供後面siglongjum使用 /* ** handler:一個訊號處理程式 */ static void handl