Chapter02-整數(shù)的運(yùn)算

1.無符號(hào)數(shù)的加法運(yùn)算

  • 下面兩個(gè)無符號(hào)數(shù)相加我們希望得到的結(jié)果是256,但是實(shí)際的運(yùn)行結(jié)果卻是0。原因是:a+b的和已經(jīng)超過了unsigned char類型所能表示的最大值255,我們稱這個(gè)情況為溢出。
    unsigned char a = 255;
    unsigned char b = 1;
    
    unsigned char c = a + b;
    printf("c=%d\n", c)
    
無符號(hào)數(shù)表示范圍.jpg

2.無符號(hào)數(shù)的加法溢出

  • 對(duì)于操作數(shù)x和y,兩者的取值范圍都是大于等于0,小于2的w次方。對(duì)于兩者相加的和,如果小于2的w次方,那么程序執(zhí)行的結(jié)果與實(shí)際情況一致;如果大于或等于2的w次方,此時(shí)就會(huì)發(fā)生溢出。
無符號(hào)數(shù)的溢出.jpg
  • 變量a和變量b的二進(jìn)制表示如下圖所示,為了使得運(yùn)算結(jié)果 的數(shù)據(jù)位數(shù)保持w位不變,最高位的1會(huì)被丟棄。因此,得到的結(jié)果相當(dāng)于減去2的w次方。在C語言執(zhí)行的過程中,對(duì)于溢出的情況并不會(huì)報(bào)錯(cuò)。
數(shù)據(jù)溢出原理.jpg

3.如何判斷無符號(hào)數(shù)的數(shù)據(jù)溢出

  • 由于下面函數(shù)的兩個(gè)形參x和y都是大于等于0的,因此兩者之和一定大于等于其中的任意一個(gè)數(shù)。于是,可以使用下面的代碼來判斷是否發(fā)生了溢出。如果返回值為1,表示運(yùn)算結(jié)果正常;如果返回值為0,則表示發(fā)生了溢出
    int uadd_ok(unsigned x, unsigned y) {
        unsigned sum = x + y;
        if(sum >= x)
            return 1;
        else
            return 0;  // 發(fā)生了數(shù)據(jù)溢出
    }
    
  • 上述判斷條件的正確性:由于x和y都是非負(fù)數(shù),x+y的和一定是大于或等于其中的一個(gè)數(shù)。當(dāng)發(fā)生溢出時(shí),x+y的運(yùn)行結(jié)果等于x加y減去2的w次方。根據(jù)y的取值范圍可知,y的取值是小于2的w次方。因此,y減去2的w次方是小于0。最終,非負(fù)數(shù)x加上一個(gè)小于0的數(shù)后,結(jié)果一定是小于x的。由此可以證明,當(dāng)發(fā)生數(shù)據(jù)溢出時(shí),得到的和小于其中任意一個(gè)數(shù)(x或者y)。

4.有符號(hào)數(shù)的加法運(yùn)算

  • 有符號(hào)數(shù)x和y的取值范圍如下圖所示,對(duì)于補(bǔ)碼的加法運(yùn)算,需要引入一個(gè)符號(hào)t來表示補(bǔ)碼。想要準(zhǔn)確的表示有符號(hào)數(shù)相加的結(jié)果,需要w+1位。為了避免數(shù)據(jù)大小的擴(kuò)張,最終結(jié)果將截?cái)喑蓋位來表示。有符號(hào)數(shù)的溢出分為正溢出和負(fù)溢出,當(dāng)x+y的和大于等于2的w-1次方時(shí),發(fā)生正溢出。此時(shí),得到的結(jié)果會(huì)減去2的w次方;當(dāng)x加y的和小于負(fù)的2的w-1次方時(shí),發(fā)生負(fù)溢出。此時(shí),得到的結(jié)果要加上2的w次方。
有符號(hào)數(shù)的溢出.jpg
  • 下面的代碼表示兩個(gè)有符號(hào)數(shù)相加的結(jié)果,我們期望的結(jié)果是128而實(shí)際的結(jié)果卻是-128。
    char x = 127;
    char y = 1;
    
    char z = x + y;
    printf("z=%d\n", z);  // -128,發(fā)生了正溢出
    
    
    char x = -128;
    char y = -1;
    
    char z = x + y;
    printf("z=%d\n", z);  // 127,發(fā)生了負(fù)溢出
    
正溢出.jpg
負(fù)溢出.jpg

5.如何判斷有符號(hào)數(shù)的數(shù)據(jù)溢出

  • 判斷條件:當(dāng)兩個(gè)正數(shù)相加,得到的結(jié)果為負(fù),則說明發(fā)生了正溢出;當(dāng)兩個(gè)負(fù)數(shù)相加,得到的結(jié)果為正,則說明發(fā)生了負(fù)溢出。
有符號(hào)數(shù)加法運(yùn)算數(shù)據(jù)溢出判斷.jpg

6.無符號(hào)數(shù)的乘法運(yùn)算

  • 對(duì)于w位的無符號(hào)數(shù)x和y,具體表示如下圖所示。兩者的乘積可能需要2w位表示。在C語言中,定義了無符號(hào)數(shù)乘法所產(chǎn)生的結(jié)果是w位。因此,運(yùn)行結(jié)果會(huì)截取2w中的低w位。因此,運(yùn)行結(jié)果等于x與y的乘積并對(duì)2的w次方取模。
無符號(hào)數(shù)的乘法運(yùn)算.jpg

7.有符號(hào)數(shù)的乘法運(yùn)算

  • 對(duì)于w位的有符號(hào)數(shù)x和y,具體表示如下圖所示。兩者的乘積可能需要2w位表示。在C語言中,定義了有符號(hào)數(shù)乘法所產(chǎn)生的結(jié)果是w位。因此,運(yùn)行結(jié)果會(huì)截取2w中的低w位。因此,運(yùn)行結(jié)果等于x與y的乘積并對(duì)2的w次方取模,然后將無符號(hào)數(shù)轉(zhuǎn)換成有符號(hào)數(shù)。
有符號(hào)數(shù)的乘法運(yùn)算.jpg
  • 由于乘法指令的執(zhí)行需要多個(gè)時(shí)鐘周期,很多C語言的編譯器試圖使用移位和加法、減法來代替整數(shù)乘法的操作。對(duì)整數(shù)的除法運(yùn)算使用的右移運(yùn)算,無符號(hào)數(shù)采用的是邏輯右移,而有符號(hào)數(shù)采用的是算術(shù)右移。
整數(shù)乘以2的冪轉(zhuǎn)換為左移操作.jpg
整數(shù)的乘法轉(zhuǎn)換為左移和加減法運(yùn)算.jpg
  • 整數(shù)的除法可能遇到除不盡的情況,結(jié)果總是會(huì)朝著向0的方向進(jìn)行舍入。對(duì)于x大于等于0且y大于0的情況,結(jié)果總會(huì)是向下舍入;當(dāng)x小于0且y大于0時(shí),結(jié)果將向上舍入。
整數(shù)的取整運(yùn)算.jpg

8.參考資料

[1].本文圖片來源,侵權(quán)必刪:https://www.bilibili.com/video/BV13Z4y1V734/?spm_id_from=333.788&vd_source=9e048d0319d701d15b8120b9c8b97d2e

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容