C++中float類型的存儲

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'次
相關文章
相關標籤/搜索