爲啥8位有符號數的範圍爲“-128 — +127”?(轉載加補充)

爲什麼8位有符號數的範圍爲“-128 — +127”?(轉載加補充)

是一個困惑了我幾年的問題,它讓我對現在的教科書和老師極其不滿,從我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

發佈了233 篇原創文章 · 獲贊 31 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章