本篇博客將闡述、討論的內容:
●int
int的范圍根據計算機的不同存在16位或32位的差異,以16位舉例,最大值為1111 1111 1111 1111,也就是65535,如果出現65536,就會溢出。
●unsigned int(無符號整型)
以16位系統為例,unsigned int能存儲的數據范圍是0~65535(需要注意整數是以補碼形式存放)。其進行的是模數計算,也就是所謂的二進制相加減,計算方法和十進制加減並無區別,但是unsigned int有着正溢出和負溢出的問題。
對於正溢出與負溢出,諸多基礎概念便不再贅述,不懂的朋友可以去回顧計算機組成原理的相關知識。
這里僅舉出一個負溢出的例子:
進行自然丟棄后,可知結果為0。很明顯,產生了負溢出。
●接下來,我們說說unsigned int和int的相互轉化,代碼如下:
float sum_elements(float a[],unsigend length){
float result = 0;
for(int i = 0; i <= length - 1; i++){
result += a[i];
return result;
}
}
很顯然,計算一個數組所有元素之和。但當數組為空時,length輸入0,會返回一個存儲器錯誤。為什么呢?請看unsigned int的計算,length是unsigned int 類型,進行的是模數運算,只代表正數,如果出先了0000000(這里有32個0)-00000..01(31個0,1個1)=111…11111(32個1)=UMAX。一個本該為-1的數變成了無符號數最大值,當i取任何不為0的數都發生了非法訪問,自然出現了存儲器錯誤,並且任何數都小於UMAX,出現判別式永遠為真,進入死循環。解決辦法有兩種,做一個判斷,當傳入length<1,直接返回0 or 在之前就將length轉化為int。
●浮點數
●定點數以及定點數的缺點
用10進制表示小數早已司空見慣,那么就會想要對二進制做同樣的操作,為它也加上小數點。
但是如此的二進制小數,會出現一些問題不可避免
整數部分 | 小數部分 | 二進制(Representation) |
---|---|---|
5 | 3/4 | $101.11_2 $ |
2 | 7/8 | $10.111_2$ |
1 | 7/16 | $1.0111_2$ |
很明顯可以發現,只能准確的表示 \(x/2^k\) 的小數,而不為 \(x/2^k\) 只能近似。
十進制小數部分 | 二進制(Representation) |
---|---|
1/3 | $0.01010101[01]… _2$ |
1/5 | $0.001100110011[0011]… _2$ |
1/10 | $0.0001100110011[0011]… _2$ |
由此可見,當小數無法描述\(x/2^k\)時,二進制小數便只能取近似值(多采用close to even(靠近偶數))。
這就暴露定點數的一個重要缺點 ---- 定點數無法標准化。也就是說,關於小數點的位置無法給出一個標准的定點數計算方式,不同小數點的位置給計算定點數增加了難度。與此同時,定點數表示的范圍有限,32位的定點數,假設沒有整數位,那么所能表示的小數的最小值為:2-32,而32位浮點數僅指數位便可以表示到2-126,由此不難看出,定點數雖然精度高,但標准化和范圍大小都比較差。
所以此時便引出了浮點數來統一二進制小數的表示:
注:s:表示符號位,只用一個bit表示
M:表示尾數(significand)(frac)也表示小數位,即能准確表示小數位
E:表示指數位。
常用的float,double組成:
可以看出float有8位指數位,23位尾數位。指數最大可表示的范圍為-127~126
浮點數所表示的一個范圍:
可以得到,浮點數隨着大小的不同被分為不同種類,接近0的稱為Denormalized,較大的數字被分為Infinity。(關於Denormalized、Infinity等名詞請自行了解,這里不再做過多的贅述)。
Denormalized到NaN的變化:
浮點數相加的公式:
浮點數的加法和乘法由於近似的原因,經常無法實現加法的結合律和乘法分配律,如下所示:
(3.14+le10)-1e10=0.0,因為3.14+1e10會舍入,3.14會丟失(1e10表示1*101010)
然而3.14+(1e10-1e10)=3.14
le20*(le20-le20)=0.0
le20le20-le20le20=NaN,由於溢出的關系,可見在數字大的情況下不滿足加法結合律和乘法分配律。
最后,關於int,float,double之間相互轉換可能的問題:
當在int,float以及double格式之間進行強制轉換時,程序改變數值和位模式的原則如下(假設int為32位):
●從int轉換成float,數字不會溢出,但可能被舍入。
●從int或float轉換成double,因為double有更大的范圍(也就是可表示值得范圍),也有更高得精度(即有效位數),所以能保留精確得數值。
●從double轉換成float,因為范圍要小一些,所以值可嫩溢出為+∞或-∞。且由於精度較小,它還可能被舍入。
●從float或double轉換成int,值將會向0舍入。例如1.999將轉換為1。進一步說,值可能會溢出。C語言標准沒有對這種情況指定固定的結果。而與Inter兼容的微處理器指定位模式[10…00](字長為ω時的TMinω)為整數不確定值。一個從浮點數到整數的轉換,如果不能為該浮點數找到一個合理的整數近似值,就會產生一個這樣的值。因此,表達式(int)+le10會得到-21483648,即從一個正值變成了一個負值。
參考博主:寫代碼的柯長(CSDN)、Jamesjiang2050(博客園)