1. 程式人生 > 實用技巧 >淺談C語言整型與浮點型轉換

淺談C語言整型與浮點型轉換

本篇部落格將闡述、討論的內容:

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)
53/4101.112
27/810.1112
17/161.01112

很明顯可以發現,只能準確的表示x/2k的小數,而不為x/2k只能近似。

​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​ ​
十進位制小數部分二進位制(Representation)
1/30.01010101[01]… 2
1/50.001100110011[0011]… 2
1/100.0001100110011[0011]… 2
而為什麼會出現如上結果,就要知到1/3 和 1/5是如何計算的。

由此可見,當小數無法描述x/2k時,二進位制小數便只能取近似值(多采用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(部落格園)