為什麼8位有符號數的範圍為“-128 — +127”?(轉載加補充)
2010-06-03 11:22:57| 分類:
IT技術 | 標籤:
|字型大小大中小 訂閱
這是一個困惑了我幾年的問題,它讓我對現在的教科書和老師極其不滿,從我N年前開始摸電腦時,就幾乎在每一本C++教科書上都說,8位有符號的取值範圍是-128~+127,為什麼不是-127~+127呢,後來的java,int的聚值範圍,再32位計算,-2^31
~ +2^31-1,可是,卻從來沒有任何一本教科書或一個老師比我解釋過這個問題。 原因沒有在工作上或者是什麼地方直接遇到它,所以我也一直忽略它,但心裡總是有一根刺.直到剛才!!!!
就是剛才,無聊之極,在看彙編的書時,又遇到它了,但一如以往,書上直接地,有心地,明顯地繞過了這個問題,真是可惡啊.
幾經周折,終於把它搞清楚了:
其實,它是電腦底層為了實現數值運算而決定的,涉及非常非常基礎的原碼,反碼,補碼知識,一般(99.9999%)都不會用得上. 那0.0001%,估計也就是電腦考試了.
話說:
用2^8來表示不帶正負號的整數的話,全世界的理解都是0 - 255了,那麼,有符號呢? 用最高位表示符號,0為+,1為-,那麼,正常的理解就是 -127 至 +127 了.
這就是原碼了,值得一提的是,原碼的弱點,有2個0,即+0和-0,還有就是,進行異號相加或同號相減時,比較笨蛋,先要判斷2個數的絕對值大小,然後進行加減操作,最後運算結果的符號還要與大的符號相同.
於是乎,反碼產生了,原因....略,反正,沒過多久,反碼就成為了過濾產物,也就是,後來補碼出現了.
補碼的知識不說述,只說有關+127和-128的.
官方的定義 [-2^(n-1),2(n-1)-1],補碼的0沒有正負之分.原因呢?沒有一本書上有說,這也是我這麼火的原因,但通過思考,google,再思考,很快找到答案:
首先,難不免幹點白癡般地事情,窮舉一下...
正數,原碼跟補碼一樣
+127, 0111 1111
+126, 0111 1110
+125, 0111 1101
+124, 0111 1100
+123, 0111 1011
+122, 0111 1010
...
+4, 0000 0100
+3, 0000 0011
+2, 0000 0010
+1, 0000 0001
0, 0000 0000 (無正負之分)
下面是負數了,值,原碼,符號位不變其它取反,+1
-1, 1000 0001, 1111 1110, 1111 1111
-2, 1000 0010, 1111 1101, 1111 1110
-3, 1000 0011, 1111 1100, 1111 1101
-4, 1000 0100, 1111 1011, 1111 1100
-5, 1000 0101, 1111 1010, 1111 1011
-6, 1000 0110, 1111 1001, 1111 1010
-7, 1000 0111, 1111 1000, 1111 1001
-8, 1000 1000, 1111 0111, 1111 1000
-9, 1000 1001, 1111 0110, 1111 0111
-10, 1000 1010, 1111 0101, 1111 0110
-11, 1000 1011, 1111 0100, 1111 0101
-12, 1000 1100, 1111 0011, 1111 0100
-13, 1000 1101, 1111 0010, 1111 0011
-14, 1000 1110, 1111 0001, 1111 0010
-15, 1000 1111, 1111 0000, 1111 0001
-16, 1001 0000, 1110 1111, 1111 0000
-17, 1001 0001, 1110 1110, 1110 1111
...
-24, 1001 1000, 1110 0111, 1110 1000
...
-99, 1110 0011, 1001 1100, 1110 0100
...
-124, 1111 1100, 1000 0011, 1111 1101
-125, 1111 1101, 1000 0010, 1000 0011
-126, 1111 1110, 1000 0001, 1000 0010
-127, 1111 1111, 1000 0000, 1000 0001
看出點什麼了沒有?
如果沒有,那麼,給個提示, 再繼續下去,下一個補碼是什麼呢?
當然是
-128, 先略過,再略過, 1000 0000
1000 0000,那麼,它的原碼是什麼呢?
從補碼求原碼的方法跟原碼求補碼是一樣的
先保留符號位其它求反: 1111 1111, 再加1:11000 0000, 超過了8位了
對,用8位元的原碼在這裡已經無法表示了
關鍵就在這裡,補碼 1000 0000 為 -128 是不用懷疑的(上面的窮舉),
那麼,回到原碼處, 它的原碼也是 1000 0000(超出的自動丟失),
1000 0000 在原碼錶示什麼呢? -0, 但補碼卻規定0沒有正負之分
轉換一下思路,看看電腦裡,是怎麼運算的:
對於負數,先取絕對值,然後求反,加一
-128 -> 128 -> 1000 0000 -> 0111 1111 -> 1000 0000
現在明確了吧.
所以, 8位有符號的整數取值範圍的補碼錶示
1000 0000 到 0000 0000, 再到 0111 1111
即 -128 到 0, 再到 127
最終 -128 ~ +127
感謝google,感謝被我瀏覽過又關閉了還忘記了姓名的廣大的blog們,CSDN(那上面也有些不錯的東西)
-------------------------------------------------------------------
補充說明
“一個n位有符號int型數值,其範圍為-2^(n-1) ——2^(n-1) -1”,對於這個問題,很多人都是困惑不已。其實,導致此情況的根本原因是“人們解決問題時,習慣以人的思維思考問題,但是,電腦本身確實以機器的思維進行處理的”。在這裡,就表現為“電腦對資料的處理其實是以‘補碼’的形式,而非日常生活中人們進行數學運算所採用的‘原碼’的形式”,但是,人們在對“此數值範圍”進行處理的時候,卻習慣性的採用了“原碼作為機器碼”。
在曆史上,針對“數值”計算,電腦先後採用過3種機器碼——原碼、反碼和補碼。
具體表示如下:
1. 原碼 最高位為符號位,其餘為對應數值的絕對值的位元值表示;
2. 反碼 最高位為符號位,正數=原碼 負數=符號位+原碼對應的其他位元取反;
3. 補碼 最高位為符號位,正數=原碼 負數=反碼+1。
其中,符號位“0為+,1為-”。
因為,電腦為資料類型分配了n位,超過n位的數值會被自動捨棄,那麼, 就可以發現,現在電腦系統中採用的補碼,克服了“原碼中存在+0和-0”的情況,僅表現為一個0,(對於8位元據類型,即為8個0,具體推導見轉載內容的窮舉,-128計算補碼時,產生的9位元據11000 0000--補碼1000 0000)。
對應而言,8位有符號位元值的範圍就成為了“-2^(8-1) ——2^(8-1) -1”,即“-128——+127”。
問題的關鍵就在這裡了,“電腦為有符號int型數值分配固定的位元n儲存資料,當資料位元數大於n時,大於n的位元被自動捨棄”。這就是導致數值範圍為“-2^(n-1) ——2^(n-1) -1”的原因,從而,也導致了資料範圍中“模”概念的產生。
註:
1. 模
“模”實質上是計量器產生“溢出”的量,它的值在計量器上表示不出來,計量器上只能表示出模的餘數。例如,雖然時鐘的模=12,但是在時鐘的指標並不能真正指向“12點”,“12點”的位置和“0點”是重合的,即12點以0點表示。
換句話說,時鐘的範圍“0——11”,則模為12。
對應而言,n位無符號數值的計量範圍0~2^(n)-1,模=2^(n); n位有符號數值,數值範圍-2^(n-1) ——2^(n-1) -1,則模為2^(n-1)。舉例說明,8位無符號數值,二進位模為2^8;8位有符號數值,表示的數值範圍為0——2^8-1。
2. 補碼的運算規則
[X+Y]補 = [X]補 + [Y]補 ;[X-Y]補 = [X]補 - [Y]補 = [X]補 + [-Y]補。
希望對大家有所協助!
參考:
http://baike.baidu.com/view/377340.html?wtp=tt
http://baike.baidu.com/view/742694.htm?fr=ala0_1
http://baike.baidu.com/view/60480.htm
http://www.cppblog.com/goal00001111/archive/2010/04/16/112745.html等