最近開始復習基礎知識,發現才看到浮點數就一大堆疑問,上網搜了一大堆不是這個錯就是那個錯,上機一驗證發現都有問題,干脆自己整理整理這方面知識,因為是用代碼驗證的,所以又涉及到與位操作符和移位操作符的內容。
Visual C++中,float的32位這樣分: 符號位(S):1位 階碼(E):8位 尾數(M):23位
其中符號位就是正負號(float和double都是不能和unsigned合用的,所以一定有正負)。
先介紹尾數,尾數是一個1.MMMMMMM……(23個M),所以尾數是一個>=1&&<=2的數的小數部分,翻譯成尾數還是很恰當的。
我們可以把小數看成 V=+/- 1.MMMMMMM……(23個M) * (2^E’) 這種形式,那階碼的意義就出來了,是2的冪次,因為有8位,所以能夠表示[0,255],為了表示負數,這里采用移碼方式(而不是整數中的補碼方式,理由還沒想清楚),即實際的2^E’的E’是階碼E-127,即范圍變成[-127,128](很多資料上說[-128,127]是錯誤的),直觀的說E'表示1.MMMMMMM……小數點的移位,正數則小數點向右移,負數小數點向左移。
用一段輸出float內存值的代碼來驗證下:
#include <iostream> #include <string> using namespace std; int main(){ float f = -3.0f; unsigned int* pa = (unsigned int*)(&f); for(int i = 31;i >= 0;i--) cout << (*pa>>i & 0x01) << (i==31||i==23? "- ": " "); cout << "\n "; return 0; }
-3.0=- 1.1000000(一共22個0) * (2^1) (1.1在十進制中表示1.5,E'=1 得到E=128=10000000)
寫這段驗證代碼的時候順便復習了下位與操作符(&)和移位操作符(<< >>),以前完全沒注意啊啊啊啊啊啊啊啊
(1)float、double、long double等類型不允許直接進行位與操作符啊,可用間接的方法變通,如float取地址(也是&符號)轉換為unsigned int類型,再用取值操作符(*),這樣編譯器會以為是unsigned int類型。
(2)使用int、short、long移位時最好加上unsigned,這樣就是匯編中邏輯移位(即全部移位),如果不加unsigned情況就較為復雜,正數全是邏輯移位,負數左移時保持符號位為1、右邊補0,負數右移時保持符號位為1,左邊補1,所以-1不管怎么右移都是-1。
(3)位與操作符就是將兩個數進行與操作,&0x01就相當於掩碼取出最后一位,其他位置成0
(4)位與操作符&的操作優先級小於移位操作符,但移位操作符小於取地址操作符&(取值操作符*),所以上面代碼不會出錯