C++中float用32位來表示,f = (-1)^S * T * 2^E,S是符號位,T是尾數,E是指數


首先我們把f表示成科學計數法的形式,然后再寫出其在內存中的表示,在這里T寫成1.XXX的形式,所以可以表示24位尾數
舉例來說 f = 14.25f = (1110.01)B = (1.11001*2^3)B 所以符號位S = 0, T = 11001B, E = 3 = 11B
另外指數可以為負數,在C++中,是把指數加上127來存儲的,即E= E+ 127 = 130 = 10000010B
即







在x86系統中,小端模式,因此在內存中的存儲為0x00|00|64|41
那么我們可以計算一下C++中float表示的范圍了,可以先列出S,T,E的取值范圍
S = 0 或者1
T = 最小0 最大 1-2^-32
S = 最小-127 最大128
絕對值最大為 ABSMAX = [1-(2^-32)]* 2^128 約等於 3.4E+38
絕對值最小為 ABSMIN = 1.0 * 2^(-127)
所以取值范圍是 [-ABSMAX, -ABSMIN] 和 [ABSMIN, ABSMAX]
另外對於0.0f,內存中是以全0表示
附float與int之間的轉換,首先需要說明的是int與char在C++中都是以補碼形式存儲
int->float
把int寫成科學計數法形式,比如 i = -128 = -1.0*(2^7) B 所以符號位S = 1, T = 0B, E = 7 = 111B
E = E+ 127 = (10000110)B
在x86系統中,小端模式,因此在內存中的存儲為0x00|00|00|C3,而int類型的存儲為0x80|ff|ff|ff(補碼形式)
注意在整個過程中int要進行右移操作,int有1位符號位,31位數字位,但是float只有24位尾數,所以可能造成精度下降
float->int
int表示的范圍是[-2^31, 2^31-1],因此只是落在此范圍中的float轉成int有實際意義,否則結果是未可知的
float數字位f = (-1)^S * T * 2^E, 令T = 1.T,然后根據指數E對T進行移位操作即可,最后根據符號位S判斷結果的正負
對於f = 0,內存中以全0表示,需要單獨處理
代碼如下
float f = 40; //*(int *)(&f) = 0xFFFFFF; int p = *(int *)&f; //尾數 當然與真實的尾數左移了23位 int t = (p & 0x7FFFFF) | 0x800000; //指數 int e = (p >> 23) & 0xFF; //符號位 int s = p >> 31; if(e - 127 < -31 || e - 127 > 31) { printf("結果不可知\n"); } e = e-127-23; if(e > 0)//左移 p = t << e; else if(e < 0)//右移 p = t >> -e; if(s < 0) p = -p; if(f == 0) p = 0;
在上述代碼中,不管是左移還是右移當移動次數大於等於32時,會得到意想不到的結果,實際上有如下結論
如果被移動對象的長度是n位,那么移動計數必須大於等於0,並且嚴格小於n。
對於寬度為m的類型, 在X86上運行,移動次數為n,若n>=m,結果相當於移動 n&(m-1) 次
若n < 0, 則存在最小的k,使得k*m + n = n' > 0,相當於移動n'次