C語言系列(二)有符號數和無符號數詳解
1、你自已決定是否需要有正負:
就像我們必須決定某個量使用整數還是實數,使用多大的範圍數一樣,我們必須自已決定某個量是否需要正負。如果這個量不會有負值,那麼我們可以定它為帶正負的型別。
在計算機中,可以區分正負的型別,稱為有符型別(signed),無正負的型別(只有正值),稱為無符型別。 (unsigned)數值型別分為整型或實型,其中整型又分為無符型別或有符型別,而實型則只有符型別。 字元型別也分為有符和無符型別。 比如有兩個量,年齡和庫存,我們可以定前者為無符的字元型別,後者定為有符的整數型別。
2.使用二制數中的最高位表示正負:
首先得知道最高位是哪一位?1個位元組的型別,如字元型別,最高位是第7位,2個位元組的數,最高位是第15位,4個位元組的數,最高位是第31位。不同長度的數值型別,其最高位也就不同,但總是最左邊的那位(如下示意)。字元型別固定是1個位元組,所以最高位總是第7位。
(紅色為最高位)
單位元組數:
11111111
雙位元組數:
11111111 11111111
四位元組數:
11111111 11111111 11111111 11111111
當我們指定一個數量是無符號型別時,那麼其最高位的1或0,和其它位一樣,用來表示該數的大小。
當我們指定一個數量是有符號型別時,此時,最高數稱為“符號位”。為1時,表示該數為負值,為0時表示為正值。
3.無符號數和有符號數的範圍區別:
無符號數中,所有的位都用於直接表示該值的大小。有符號數中最高位用於表示正負,所以,當為正值時,該數的最大值就會變小。我們舉一個位元組的數值對比:
無符號數: 11111111 值:255
有符號數: 01111111 值:127
eg:(本屌實在不知道怎麼用md語法來打出數學公式,2的冪次方)
同樣是一個位元組,無符號數的最大值是255,而有符號數的最大值是127。原因是有符號數中的最高位被挪去表示符號了。並且,我們知道,最高位的權值也是最高的(對於1位元組數來說是2的7次方=128),所以僅僅少於一位,最大值一下子減半。
不過,有符號數的長處是它可以表示負數。因此,雖然它的在最大值縮水了,卻在負值的方向出現了伸展。我們仍一個位元組的數值對比:
無符號數: 0 —————– 255
有符號數: -128 ——— 0 ———- 127
同樣是一個位元組,無符號的最小值是 0 ,而有符號數的最小值是-128。
所以二者能表達的不同的數值的個數都一樣是256個。只不過前者表達的是0到255這256個數,後者表達的
是-128到+127這256個數。
一個有符號的資料型別的最小值是如何計算出來的呢?
有符號的資料型別的最大值的計算方法完全和無符號一樣,只不過它少了一個最高位(見第3點)。但在負值
範圍內,數值的計算方法不能直接使用1* 26 + 1* 25 的公式進行轉換。
在計算機中,負數除為最高位為1以外,還採用補碼形式進行表達。所以在計算其值前,需要對補碼進行還原。 這裡,先直觀地看一眼補碼的形式:
在10進制中:1 表示正1,而加上負號:-1 表示和1相對的負值。
那麼,我們會很容易認為在2進制中(1個位元組): 0000 0001 表示正1,則高位為1後:1000 0001應該表示-1。
然而,事實上計算機中的規定有些相反,請看下錶:
二進位制(1位元組) | 十進位制值 |
---|---|
10000000 | -128 |
10000001 | -127 |
10000010 | -126 |
10000011 | -125 |
10000100 | -124 |
…… | …… |
11111110 | -2 |
11111111 | -1 |
首先我們看到,從-1到-128,其二進位制的最高位都是1,正如我們前面說的,負數最高位為1,然後我們覺得有點奇怪了,1000 0000 並沒有用來表示 0;而 1000 0001也不是拿來直觀地表示-1,事實上,-1用1111 1111來表示。
怎麼理解這個問題呢?先問一句是-1大還是-128大?
當然是-1大,那麼,1111 1111 -1是什麼呢? 和現實中的計算結果完全一致。1111 1111 -1=1111 1110,而1111 1110 就是-2,就這樣一直減下去,當見到只剩最高位用於表示符號的1意外,其他低位全為0時,就是最小的負值,在一位元組中,最小的負值是1000 0000,也就是-128。
我們以-1位例,來看看不同位元組數的整數中,如何表達-1這個數;
位元組數 | 二進位制值 | 十進位制值 |
---|---|---|
單位元組數 | 11111111 | -1 |
雙位元組數 | 11111111 11111111 | -1 |
四位元組數 | 11111111 11111111 11111111 11111111 | -1 |
可能有些人看到這裡,就已經混了,為什麼呢?1111 1111 有時表示255,有時又表示-1?所以我再強調 前面說的第二點,你自己決定一個數是有符號還是無符號的,寫程式時,指定一個量是有符號的,那麼當這個量的二進位制各位上的數都是1時,它表示的數就是-1;相反,如果事先宣告這個量是無符號的, 此時它表示的就是該量允許的最大值,對於一個位元組的數來說,最大值就是255。
我們已經知道計算機中,所有資料最終都是使用二進位制數表達。 也已經學會如何將一個10進位制數如何轉換為二進位制數。 不過,我們仍然沒有學習一個負數如何用二進位制表達。 比如,假設有一 int 型別的數,值為5,那麼,我們知道它在計算機中表示為:
00000000 00000000 00000000 00000101
5轉換成二制是101,不過int型別的數佔用4位元組(32位),所以前面填了一堆0。 現在想知道,-5在計算機中如何表示? 在計算機中,負數以其正值的補碼形式表達。 什麼叫補碼呢?這得從原碼,反碼說起。
原碼:一個整數,按照絕對值大小轉換成的二進位制數,最高為為符號位,稱為原碼。 紅色為符號位
比如:
00000000 00000000 00000000 00000101 是 5的原碼。 10000000 00000000 00000000 00000101 是-5的原碼
反碼: 將二進位制除符號位數按位取反,所得的新二進位制數稱為原二進位制數的反碼。 正數的反碼為原碼,負數的反碼是原碼符號位外按位取反。
取反操作指:原為1,得0;原為0,得1。(1變0; 0變1)
正數:正數的反碼與原碼相同。
負數:負數的反碼,符號位為“1”,數值部分按位取反。
比如:將10000000 00000000 00000000 00000101除符號位每一位取反,
得11111111 11111111 11111111 11111010。
這時候我們稱:11111111 11111111 11111111 11111010 是 10000000 00000000 00000000 00000101 的反碼。
反碼是相互的, 所以也可稱:
11111111 11111111 11111111 11111010 和 10000000 00000000 00000000 00000101 互為反碼。
補碼: 反碼加1稱為補碼。 (如果反碼最後一位是1得話就向前加1)
1. 正數:正數的補碼和原碼相同。
2. 負數:按照規則來
也就是說,要得到一個數的補碼,先得到反碼,然後將反碼加上1,所得數稱為補碼。
11111111 11111111 11111111 11111010 是 10000000 00000000 00000000 00000101(-5) 的反碼。
加1得11111111 11111111 11111111 11111011
所以,-5 在計算機中表達為:11111111 11111111 11111111 11111011。轉換為十六
進位制:0xFFFFFFFB。
再舉一例,我們來看整數-1在計算機中如何表示。
假設這也是一個int型別,那麼:
1、先取-1的原碼: 10000000 00000000 00000000 00000001
2、除符號位取反得反碼:11111111 11111111 11111111 11111110
3、加1得補碼: 11111111 11111111 11111111 11111111 可見,-1在計算機裡用二進位制表達就是全1。16進製為:0xFFFFFF。
計算機中帶有符號數用補碼錶示的優點:
1、負數的補碼與對應正數的補碼之間的轉換可以用同一種方法——求補運算完成,可以簡化硬體;
2、可將減法變為加法,省去減法器;
3、無符號數及帶符號數的加法運算可以用同一電路完成。
可得出一種心算求補的方法——從最低位開始至找到的第一個1均不變,符號位不變,這之間的各位“求反”(該方法僅用於做題)
方法 | 例子1 | 列子2 |
---|---|---|
1,從右邊開始,找到第一個“1” | 10101001 | 10101100 |
2,從這個“1”之後開始到最左邊取反(不包括符號位,也就是最高位) | 11010111 | 11010100 |
注意:(如果反碼最後一位是1得話就向前加1)