關於java中byte取值範圍最小值為什麼是-128而不是-127引發的思考

2021-01-07 友蘭之家

我們都知道java 的byte佔4個字節,1個字節8位。而計算機表示數據都是以二進位的形式表示。那麼一個byte表示的二進位應該為0000 0000 -1111 1111,又因為最高位代表符號位,那麼一個byte表示的範圍就應該為(-2^7-1)-(2^7-1)即-127到127怎麼會有-128呢?

其實也沒有什麼好說的,這就是規定的,包括short,int,long這些都是一樣!那麼為什麼這麼規定呢?有興趣的可以繼續往下看。我們一步一步的分析:

1.計算機沒有減法運算,所謂的做減法其實是通過加法來運算的。那麼怎麼將減法變成加法來運算呢?這裡涉及到一個模的概念。通常的解釋就是用的一個鐘錶來解釋的。

比如現在是3點鐘,我們現在要讓它指到1點,我們可以怎麼辦呢?有兩種方式:

將時針往後撥兩個小時即 3-2=1;將時針順時針撥10個小時即3+10同樣指向了1點。是否明白了一點呢,計算機將減法變成加法採用的主要就是這種方式!

那麼計算機怎麼將3-2變成3+10的呢,怎麼求出這個10的呢。這裡就涉及到了一個模,在這裡這個模就是12。這個12在這個時鐘中就代表最大值,通過12-2就是等於10了。當然剛說了計算機沒有減法,這裡自然不會是12-2這麼算。需要清楚計算機怎麼算的繼續往下看:

我們都知道計算機裡負數是以補碼的形式存在的,正數的補碼是其本身,計算機加法是補碼相加。

這裡需要重溫一下:

負數的補碼是其反碼加1.負數的反碼是除符號位外,其餘位數安位取反。正數的補碼,反碼,原碼均相同。那麼我們來看看(byte)(3-2)這個在計算機裡面是怎麼計算的呢?我們這裡是以byte來討論的所以是以8位二進位來表示:

3->0000 0011(原/反/補)

(-2)->1000 0010(原)->1111 1101(反)+1->1111 1110(補碼)

所以3-2=0000 0011+1111 1110(補碼)按位相加=0000 0001(補碼)(符號位相加溢出留0)

注意:補碼相加時符號位進行了計算的。

上面的0000 0001就是3-2在計算機裡保存的結果,還需要轉換為原碼,因為符號位是0代表正數,原碼也是0000 0001所以顯示為10進位就是1.

看了上面的過程,我們來梳理一下,計算機為什麼要將負數保存為補碼的形式。

我們之前看了關於時針的問題即3-2=3+10等於1點。

那麼計算機將負數變成補碼也是這個原因,希望通過與補碼相加來將減法變成加法,因為計算機沒有減法。

我們上面看了,時針的模是12那麼byte的模是多少呢?我們可以通過計算獲取,參照

3-2=1;

3+10=13;

那麼根據時鐘的模就是10+2等於12的計算方式:

同理計算機中: 3-2=0000 0011+1111 1110(補碼)

其中0000 0011+1111 1110(補碼)類比上面的3+10;

那麼btye的模=1111 1110(補碼)+0000 0010(2的原碼)=1 0000 0000(2的8次方)=256,(注意此處沒有區分符號位,因為計算機計算補碼相加時符號位也是相加了的,需保持一致)這樣在byte範圍內計算結果才不會出問題。不過你會發現有9位了,對就是9位。但這並不影響因為它只是byte類型計算時用的模,只要byte類型的數值是在8位以內就行。

那麼我們再反過來看,為什麼時鐘上 3+10=13與3-2=1相等了呢,顯然是因為13再減去了個12即13-12(模)=1.

那麼表現在計算機中就相當於溢出,即3-2=0000 0011+1111 1110(補碼)按位相加=1 0000 0001(補碼)然後捨去了1 0000 0000(模)(因為只有8位)=0000 0001(補碼)。

其實模的值是先確定好了的。我們會發現模其實就是等於2的n次方,n代碼數據類型的位數。那麼我們就不難理解為什麼負數的補碼是原碼的反碼+1了,因為這樣處理,補碼加上無符號原碼就剛好等於模即10000 0000(byte類型的模的二進位)

我們還可以根據上面推算出:補碼=模-負數的絕度值

感覺有點跑題了。總之計算機將減法轉換為加法的思想就是採用了模的思想!

那麼我們繼續看看為什麼btye最小值是-128不是-127呢?

原因是:1000 0000 表示 -0 而又有0000 0000表+0

-0顯然沒有任何意思,那麼就規定1000 0000表示成-2的7次方。這樣還可以多表示一位。

那麼用它表示-128來計算有沒有問題呢,答案肯定是沒有的,不然經過這麼久了,怕是早就出問題了。但是為什麼不會出現問題呢?

我們按平常的思路來看-128首先是個負數那麼除符號位外取反+1再保留8位的補碼是0000 0000

那麼-128+1=0000 0000+0000 0001 = 0000 0001 =1

結果顯然不對,為什麼不對,因為既然1000 0000 表示-128我們肯定不能按平常思路來算 因為正常來算的話 11000 0000才應該表示-128.

問題出在了-128的補碼計算方式上,我們可以根據上面的公式計算補碼為:模-負數的絕度值。

既然為-128那麼絕對值肯定為128。所以-128的補碼為 1 0000 0000 - 1000 0000= 1000 0000 即其本身

那麼此時 -128+1=1000 0000+0000 0001 = 1000 0001 (補碼)

再轉換成原碼1111 11111顯示出來即-127。結果正確 !

至此,結束,歡迎留言討論!

相關焦點

  • Byte字節的最小值為什麼是-128?
    hi,大家好歡迎來到大熊實驗室,今天在看書的時候突然間意識到一個嚴重的問題,那就是byte字節的最小值是-128,為什麼會這樣呢?今天就來研究一下。字節是我們在開發中使用的除了bit以外最小粒度的單位,但是關於字節的最小值是-128我一直都沒搞懂究竟是為什麼,按照我的理解一個字節最小值應該是-127,那怎麼來的-128呢?在計算機系統中,最小單位是1位,也就是1bit。
  • 為什麼int8的範圍是[-128,127]
    func main() { var a int8 = -1 var b int8 = -128 / a fmt.Println("b的值是:", b)}問b的值是多少?如果直接說 128,那可能還需要再去補補,畢竟 int8 的範圍在 『-128,127』。
  • java大於127byte值轉int
    因為java沒有無符號數,所以在byte值大於127時,java表達的是負數。例如:byte b = (byte)152;// b的值在java中表達的是:-104,二進位值是:10011000。int i = b;// i 的值 在java中表達的是:-104,二進位值是:11111111111111111111111110011000如果想要 i 的值等於152,需要以下運算:/*** byte轉int,
  • Java中byte做&0xff運算的原因及解析
    第一種情況:signed/unsigned之間的轉化java中,除了char是unsigned 兩個字節,用來表達UTF-16,此外byte/short/int/long都是signed的。取值範圍:boolean:一字節byte:(-128,127) 一字節char:(0,65535) 兩字節short:(-32768,32767)兩字節那麼在Java與別的語言編寫的程序通信時,就可能涉及到signed/unsigned之間的轉化。
  • labview之如何獲取數據類型的取值範圍
    的最大值為255,最小值為0,所以U8的取值範圍是0-255。  今天我們要討論的是如何獲取整數數據類型的取值範圍的方法:  一、計算法  我們知道U8是由一個字節(8位)構成的,U16是由2個字節(16位)構成的,以此類推,U64由8個字節構成(64位)。因此對於整型無符號數的取值範圍很容易計算出來,無符號整數的最小值均為0,最大值可以通過計算得到。
  • Java 教程|byte 轉換 int 時為何與 0xff 進行與運算
    其原因在於:1. byte的大小為 8bits 而 int 的大小為 32bits ;2. java的二進位採用的是補碼形式 ;在這裡先溫習下計算機基礎理論:byte是一個字節保存的,有8個位,即8個0、1。
  • 一文詳解 Java 的八大基本類型!
    由於它只有32位,所以其取值範圍為-2147483648到2147483647。這數字很大嘛!所以這裡的取值範圍跟整數不是完全一樣。一般而言,double是在Java中使用浮點數的默認選擇。另一個選擇是float。
  • 老杜帶你學Java【第六課】
    和false,true表示真,false表示假 第四類:字符型 char:java中規定字符型字面量必須使用單引號括起來。1.3、8種基本數據類型中 整數型:byte short int long有什麼區別? 浮點型:float和double有什麼區別? 區別:佔用的空間大小不同。 關於計算機存儲單位? 計算機只能識別二進位。
  • Java基本數據類型
    數值類型又可以分為整數類型byte、short、int、long和浮點數類型float、double。JAVA中的數值類型不存在無符號的,它們的取值範圍是固定的,不會隨著機器硬體環境或者作業系統的改變而改變。實際上,JAVA中還存在另外一種基本類型void,它也有對應的包裝類 java.lang.Void,不過我們無法直接對它們進行操作。
  • 一文讀懂Java基本數據類型
    不同整數類型的取值範圍整數字面量(如:123,45)默認是int類型,在不超長小類型範圍的情況下,大類型的數據給小類型直接賦值(在編寫程序過程中會逐步體會)。byte b1 = 128; //錯誤的語句,超範圍賦值byte b2 = 127 // 合法賦值byte b3 = -128 // 合法賦值使用整數類型byte,short,int時要注意取值範圍,(-128~127)之間的整數字面量可以直接賦值給
  • Java【IO系列】基礎篇—9. DataInputStream和DataOutputStream
    ,即「110xxxxx」 // 則 bytearr[count] 對應的int類型的c的取值範圍是 12-13。,即「110xxxxx」 // 則 bytearr[count] 對應的int類型的c的取值範圍是 12-13。
  • 一起學JAVA——數據類型
    上一篇我們提到過,java是強數據類型語言,所有在定義變量和常量時必須指定數據類型。java到底支持哪些數據類型呢?如下圖數據類型分類原始類型(基本類型)整數:byte 1個字節,最小值:-128,最大值:127short 2個字節,最小值:-32768,最大值:
  • 大數據語言,Java的八大基本數據類型
    Java中的數據類型,分為引用類型和基本數據類型。>整數類型有byte,short,int,long,都是有符號(補碼)整數(即能表示負數).整數字面量(127-128)默認是int類型,如果不超出聲明類型的範圍,則可以給出小類型直接賦值(不需要強記,在編寫程序過程中會逐漸理解)。使用整數類型要注意取值範圍,(-128~127)之間的整數字面量可以直接賦值給byte類型,Java會自動處理符號位,同理,short類型也是一樣的(極少使用)。
  • 五分鐘的java基礎考點速記(不包含語法)
    •數組的類型是以"["開頭的,例如int數組->[I,另外多維數組和一維數組是兩個類->[I 和 [[I•數組對象的創建是根據jvm指令創建的•newarray:創建數組對象•multinewarray:創建多個數組對象基本數據類型•關於boolean:jvm中會使用0,1兩個int值來表示boolean類型,至於boolean數組則是通過讀寫btye數組來實現的類型大小取值範圍包裝器
  • C語言中signed char類型,能表示-128到127,為什麼負數多一位?
    但是很多教科書上卻說 signed char 類型能夠表示的數值範圍為 -128 到 127,類似的還有 signed short 類型能夠表示的數值範圍為 -32768 到 32767,signed int 類型能夠表示的數值範圍為 -2147483648 到 2147483647,為什麼有符號的整數類型,負數部分總是比整數部分多出一個數呢?
  • 「軟帝學院」Java怎麼學?從零開始學Java!
    >o 引用數據類型§ 面向對象部分講解· C:基本數據類型分類(4類8種)o 整數型§ byte 佔一個字節 -128到127§ short 佔兩個字 -2^15~2^15-1;Java語言基礎(數據類型轉換之隱式轉換)(掌握)· A:案例演示o a:int + into b:byte + int· B:Java中的默認轉換規則o 取值範圍小的數據類型與取值範圍大的數據類型進行運算
  • 談一談Java中100==100為true?
    這是因為在 Integer.java 類中有一個私有內部類 IntegerCache.java,它用來緩存取值範圍在 -128到127 之間的所有的整數對象,如果值的範圍在-128到127之間,它就從高速緩存返回實例,如果不在,則創建新的 Integer 對象, 這就是 上述 變量 a 與 b 比較結果為 false ,而變量 c 與 d 的比較結果 為true 的原因。
  • 老杜帶你學Java【第十課】
    第四:編寫HelloWorld.java程序。 第五:javac進行編譯: javac命令在使用的時候 javac + java源文件的路徑(注意:路徑包括絕對和相對。) 第六:java命令進行運行 java 類名 (一定要注意:這裡不是路徑。
  • 為什麼阿里巴巴Java開發手冊強制整型包裝類對象值用equals比較?
    在閱讀《阿里巴巴Java開發手冊》時,發現有一條關於整型包裝類對象之間值比較的規約,具體內容如下:這條建議非常值得大家關注, 而且該問題在 Java 面試中十分常見。還需要思考以下幾個問題:如果不看《阿里巴巴Java開發手冊》,如何知道 Integer var = ? 會緩存 -128 到 127 之間的賦值?為什麼會緩存這個範圍的賦值?
  • 每日一課 | Java DataInputStream readByte()方法與示例
    DataInputStream類readByte()方法 readByte()方法在java.io包中可用。readByte()方法在讀取字節時可能會引發異常。如果未打開此流,則可能引發此異常。當此流到達其端點時,可能引發此異常。