(byte)1658385462>>16=-40,怎么算的?-創(chuàng)新互聯(lián)

我們提供的服務(wù)有:成都網(wǎng)站制作、成都做網(wǎng)站、外貿(mào)營(yíng)銷網(wǎng)站建設(shè)、微信公眾號(hào)開(kāi)發(fā)、網(wǎng)站優(yōu)化、網(wǎng)站認(rèn)證、武陟ssl等。為上1000家企事業(yè)單位解決了網(wǎng)站和推廣的問(wèn)題。提供周到的售前咨詢和貼心的售后服務(wù),是有科學(xué)管理、有技術(shù)的武陟網(wǎng)站制作公司正文

在 Github 項(xiàng)目mongo-java-driver有一個(gè)類ObjectId.java,它的作用是生成唯一 id 的,它的核心實(shí)現(xiàn)是下面這樣一段代碼 [1]:

public void putToByteBuffer(final ByteBuffer buffer) {notNull("buffer", buffer);
    isTrueArgument("buffer.remaining() >=12", buffer.remaining() >= OBJECT_ID_LENGTH);

    buffer.put(int3(timestamp));
    buffer.put(int2(timestamp));
    buffer.put(int1(timestamp));
    buffer.put(int0(timestamp));
    buffer.put(int2(randomValue1));
    buffer.put(int1(randomValue1));
    buffer.put(int0(randomValue1));
    buffer.put(short1(randomValue2));
    buffer.put(short0(randomValue2));
    buffer.put(int2(counter));
    buffer.put(int1(counter));
    buffer.put(int0(counter));
}

上述代碼中的int2()方法定義如下:

private static byte int2(int x) {return (byte) (x >>16);
}

取當(dāng)前時(shí)間戳(秒)1658385462,我們來(lái)測(cè)試一下該方法:

@Test
public void test() {System.out.println(int2(1658385462)); // -40
}

得到的結(jié)果是 -40。即:(byte) 1658385462 >>16 = -40。

這是怎么算出來(lái)的?

計(jì)算過(guò)程

1、首先,計(jì)算機(jī)要將 1658385462 轉(zhuǎn)換為二進(jìn)制數(shù)。

因?yàn)?int 為 4 字節(jié) 32 位,對(duì)應(yīng)二進(jìn)制結(jié)果如下:

0110 0010 1101 1000 1111 0100 0011 0110

2、執(zhí)行 >>16 運(yùn)算。

運(yùn)算結(jié)果是 0110 0010 1101 1000。

0110 0010 1101 1000 1111 0100 0011 0110 >>16 = 0110 0010 1101 1000

3、因?yàn)橛?jì)算機(jī)存儲(chǔ)補(bǔ)位,所以需將其轉(zhuǎn)為補(bǔ)位。

正數(shù)的補(bǔ)碼就是其本身,補(bǔ)碼是:0110 0010 1101 1000。

4、因?yàn)?byte 為 1 字節(jié) 8 位,所以強(qiáng)制轉(zhuǎn)換時(shí)計(jì)算機(jī)只保留其后 8 位。

保留 8 位的結(jié)果是:1101 1000。

5、保留 8位后的數(shù)值仍然是補(bǔ)位,而要展示給用戶需轉(zhuǎn)換成原位。

補(bǔ):1101 1000
反:1101 0111
原:1010 1000

6、最高位 1 表示負(fù)數(shù),將 010 1000 轉(zhuǎn)換成十進(jìn)制數(shù),則為 -40。

什么是原碼、反碼、補(bǔ)碼?

原碼:原碼就是符號(hào)位加上真值的絕對(duì)值,即用第一位表示符號(hào),其余位表示值。

反碼:正數(shù)的反碼是其本身。負(fù)數(shù)的反碼是在其原碼的基礎(chǔ)上,符號(hào)位不變,其余各位取反。

補(bǔ)碼:正數(shù)的補(bǔ)碼就是其本身。負(fù)數(shù)的補(bǔ)碼是在其原碼的基礎(chǔ)上,符號(hào)位不變,其余各位取反,最后+1。

從原碼、反碼、補(bǔ)碼的表示方式不難看出,原碼才是人眼最直觀能看出值的表示方式,那么為什么還要有反碼和補(bǔ)碼呢?

答案是為了簡(jiǎn)化計(jì)算機(jī)集成電路的設(shè)計(jì)。

我們?nèi)四X是可以辨別第一位是符號(hào)位的,在計(jì)算的時(shí)候我們會(huì)根據(jù)符號(hào)位,選擇對(duì)真值區(qū)域的加減。但是對(duì)于計(jì)算機(jī),辨別“符號(hào)位”顯然會(huì)讓計(jì)算機(jī)的基礎(chǔ)電路設(shè)計(jì)變得十分復(fù)雜,于是人們想出了將符號(hào)位也參與運(yùn)算的方法。

我們知道,根據(jù)運(yùn)算法則:減去一個(gè)正數(shù)等于加上一個(gè)負(fù)數(shù),即:1-1 = 1 + (-1) = 0,所以機(jī)器可以只有加法而沒(méi)有減法,這樣計(jì)算機(jī)運(yùn)算的設(shè)計(jì)就更簡(jiǎn)單了。此外,由于現(xiàn)階段計(jì)算機(jī) CPU 擅長(zhǎng)做加法運(yùn)算,CPU 硬件實(shí)現(xiàn)減法要復(fù)雜得多,而且運(yùn)算效率很低,所以我們偷懶只討論加法運(yùn)算。說(shuō)不定以后發(fā)明了減法加速硬件,那就另當(dāng)別論了。

為什么要有反碼?

于是人們開(kāi)始探索將符號(hào)位參與運(yùn)算,并且只保留加法的方法。 首先來(lái)看原碼:計(jì)算十進(jìn)制的表達(dá)式:1-1=0。

1 - 1
= 1 + (-1) = [00000001]原 + [10000001]原
= [10000010]原
= -2

如果用原碼表示,讓符號(hào)位也參與計(jì)算,顯然對(duì)于減法來(lái)說(shuō),結(jié)果是不正確的。這也就是為何計(jì)算機(jī)內(nèi)部不使用原碼表示一個(gè)數(shù)。

為了解決原碼做減法的問(wèn)題,出現(xiàn)了反碼。

1 - 1
= 1 + (-1)
= [0000 0001]原 + [1000 0001]原
= [0000 0001]反 + [1111 1110]反
= [1111 1111]反
= [1000 0000]原
= -0

發(fā)現(xiàn)用反碼計(jì)算減法,結(jié)果的真值部分是正確的。

為什么要有補(bǔ)碼?

用反碼計(jì)算減法,結(jié)果的真值部分是正確的。而唯一的問(wèn)題其實(shí)就出現(xiàn)在“0”這個(gè)特殊的數(shù)值上。 雖然人們理解上 +0 和 -0 是一樣的,但是 0 帶符號(hào)是沒(méi)有任何意義的。 而且會(huì)有[0000 0000]原[1000 0000]原兩個(gè)編碼表示 0。

于是出現(xiàn)了補(bǔ)碼,為了解決 0 的符號(hào)以及 0 的兩個(gè)編碼問(wèn)題:

1 - 1
= 1 + (-1)
= [0000 0001]原 + [1000 0001]原
= [0000 0001]補(bǔ) + [1111 1111]補(bǔ)
= [0000 0000]補(bǔ)
= [0000 0000]原

這樣 0 用 [0000 0000] 表示,而以前出現(xiàn)問(wèn)題的 -0 則不存在了。那另一個(gè)編碼 [1000 0000] 是否就棄用了呢?

(-1) + (-127)
= [1000 0001]原 + [1111 1111]原
= [1111 1111]補(bǔ) + [1000 0001]補(bǔ)
= [1000 0000]補(bǔ)

-1-127 的結(jié)果應(yīng)該是 -128,剛好 [1000 0000] 可以用來(lái)表示 -128。在用補(bǔ)碼運(yùn)算的結(jié)果中,[1000 0000]補(bǔ)就是 -128。

但是注意: -128 并沒(méi)有原碼和反碼表示。對(duì) -128 的補(bǔ)碼[1000 0000]補(bǔ)算出來(lái)的原碼是[0000 0000]原,這顯然是不正確的。

使用補(bǔ)碼,不僅僅修復(fù)了 0 的符號(hào)以及存在兩個(gè)編碼的問(wèn)題,而且還能夠多表示一個(gè)最低數(shù)。所以最終同樣是 8 位二進(jìn)制,使用原碼或反碼表示的范圍為 [-127, +127],而使用補(bǔ)碼表示的范圍為 [-128, 127]。

小結(jié)

我整理了本文知識(shí)消化鏈路,如下。

使用原碼計(jì)算減法的結(jié)果是錯(cuò)誤的
->出現(xiàn)了反碼
->使用反碼計(jì)算的 0 有兩個(gè),+0 和 -0
->出現(xiàn)了補(bǔ)碼

更多技術(shù)干貨,敬請(qǐng)關(guān)注公眾號(hào)「楊同學(xué)technotes」,歡迎技術(shù)交流。

文中提及的鏈接

  • [1] ObjectId#putToByteBuffer

參考資料

  • 計(jì)算機(jī)為什么要使用原碼、反碼、補(bǔ)碼
  • java中int強(qiáng)制轉(zhuǎn)byte數(shù)據(jù)溢出問(wèn)題

你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級(jí)服務(wù)器適合批量采購(gòu),新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧

網(wǎng)站名稱:(byte)1658385462>>16=-40,怎么算的?-創(chuàng)新互聯(lián)
標(biāo)題鏈接:http://bm7419.com/article0/diciio.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供云服務(wù)器、靜態(tài)網(wǎng)站、虛擬主機(jī)、標(biāo)簽優(yōu)化網(wǎng)站內(nèi)鏈、自適應(yīng)網(wǎng)站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

成都網(wǎng)站建設(shè)