淺談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)
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$
而為什么會出現如上結果,就要知到1/3 和 1/5是如何計算的。

由此可見,當小數無法描述\(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(博客園)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM