自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

計算機是怎么存儲整數(shù)的,原碼、反碼、補碼又是個啥?

存儲 存儲架構
不管是多少位的有符號整數(shù),它的最小值的絕對值一定比最大值多 1,因此八位整數(shù)的最小值是 -128,最大值是 127。事實上 10000000 表示 -128 有些人為規(guī)定的意思,但它確保了數(shù)字范圍的對稱性,并允許有效地利用二進制位來表達整數(shù)。

昨天在群里面看到耳濡目染同志發(fā)了這么一張圖。

圖片圖片

問的是 -1155459666 怎么變成 3139507630,這個問題比較有意思,雖然簡單,但涉及到了原碼、反碼、補碼相關的知識,本篇文章就來詳細解釋一下。

拋出一個問題,有兩個整數(shù) 94、78,如果讓你計算它們的和,你會怎么做?不用想,我們都會像下面這樣。

圖片圖片

十進制是逢十進一,當產(chǎn)生溢出時會往前進一位,因此結果就是 110 + 062 等于 172。但計算機在運算時會使用二進制,本質(zhì)是一樣的,只不過二進制是逢二進一。

圖片圖片

我們驗證一下。

print(94 + 78)  # 172
print(0b10101100)  # 172

另外我們知道,與運算時,如果兩個二進制位均是 1,那么結果是 1,否則結果是 0;異或運算時,如果兩個二進制位相同,結果是 0,否則結果是 1。

# 與運算,兩個二進制位均是 1,結果才是 1
print(1 & 1)  # 1
print(1 & 0)  # 0
print(0 & 1)  # 0
print(0 & 0)  # 0

# 異或運算,兩個二進制位相同,結果為 0,相異結果為 1
print(1 ^ 1)  # 0
print(1 ^ 0)  # 1
print(0 ^ 1)  # 1
print(0 ^ 0)  # 0

然后再觀察一下之前的式子。

圖片圖片

所以當兩個整數(shù)相加時,我們還可以這么做。

a = 94
b = 78
# 無進位加法
print(a ^ b)  # 16
# a + b 的進位
# 既然是進位,那么 (a & b) 要左移一位
print((a & b) << 1)  # 156
# 兩者相加
print(
    ((a & b) << 1) + (a ^ b)
)  # 172

當然兩個整數(shù)直接相加的話,這么做沒啥意義,它一般會應用于二分查找。在二分查找中,為了避免兩個整數(shù)相加溢出,求平均值的時候一般會這么做。

l = 123
r = 789
# 對于 C、Java 等語言來說,當 l、r 非常大時,相加可能會產(chǎn)生溢出
print((l + r) // 2)  # 456
# 因此一般都會這么做
print(l + (r - l) // 2)  # 456
# 但顯然還有更高效的做法
print((l & r) + ((l ^ r) >> 1))  # 456

然后來說一說原碼、反碼和補碼,不過首先我們要知道負數(shù)是如何表示的,對于一個有符號整數(shù)來說,它的最高位表示符號位。比如一個 8 位整數(shù):

圖片圖片

開頭的符號位如果為 0,則表示正數(shù),為 1 則表示負數(shù),然后剩余的有效位則表示具體的數(shù)值。比如 15 的二進制是 1111,那么:

  • 八位整數(shù) 15 的二進制就是 00001111;
  • 八位整數(shù) -15 的二進制就是 10001111;

由于 7 個位能表示的最大整數(shù)是 2 的 7 次方減 1,所以八位整數(shù)的最大值就是 127,而最小值是 -128。那么問題來了,為什么最小值是 -128 呢?這就涉及到原碼、反碼和補碼了。

計算機為了人類閱讀方便,會以原碼的形式展示,但在計算和存儲的時候則是以補碼的形式。

  • 對于正數(shù)來說,它的原碼、反碼、補碼是相同的。
  • 對于負數(shù)來說,它的反碼等于原碼的符號位不變、其它位取反(1 變 0,0 變 1),而補碼則等于反碼加 1。當然這是基于原碼求補碼,反過來也是一樣。反碼也等于補碼的符號位不變、其它位取反,然后再加 1 得到原碼,過程是一樣的。

我們舉個例子,假設兩個八位整數(shù) 17 和 -5 相加。

圖片圖片

因此 00001100 就是兩個整數(shù)的補碼相加之后的結果,也就是 12,由于是正數(shù),它的原碼和反碼也是 12。

再舉個例子,假設兩個八位整數(shù) -17 和 5 相加。

圖片圖片

相信你應該明白整個邏輯了,計算機在存儲整數(shù)時會以補碼存儲,運算也是以補碼的形式,但展示則是以原碼的形式。我們以 C 語言為例,來直觀感受一下這個過程。

#include <stdio.h>

int main(int argc, char const *argv[]) {   
    // 對于有符號整數(shù)來說,最高位表示符號位
    // 但對于無符號整數(shù)來說,所有的位都是有效位
    // 所以無符號八位整數(shù)的范圍是 0 ~ 255
    // 147 的二進制為 0b10010011
    unsigned char num = 147;
    // 由于是正數(shù),所以原碼、反碼、補碼都是 0b10010011
    printf("%hhu\n", num);  // 147
    // 但 C 語言不看你怎么存,就看你怎么讀
    // 如果以 %hhd 來讀取的話,那么會以有符號的格式打印八位整數(shù)
    // 此時 10010011 開頭的 1 就變成了符號位
    // 而計算機存儲的 10010011 是補碼,展示的時候要轉成原碼
    // 反碼:補碼符號位不變,其它位取反,等于 11101100
    // 原碼:反碼加 1,等于 11101101,轉成十進制打印就是 -109
    printf("%hhd\n", num);  // -109
    return 0;
}

我們再舉個例子:

#include <stdio.h>

int main(int argc, char const *argv[]) {   
    // 八位有符號整數(shù) -1 的原碼是 1000_0001
    // 反碼是 1111_1110,補碼是 1111_1111
    // 所以計算機在存儲 -1 的時候,存的就是二進制的 11111111
    char num = -1;
    // 但我們以無符號形式打印,那么 11111111 就全部都是有效位
    printf("%hhu\n", num);  // 255
    printf("%hhu\n", 0b11111111);  // 255

    // 再比如我們使用 16 位整數(shù),原碼是 10000000_00000001
    // 那么補碼就是 11111111_11111111
    // 如果以無符號格式打印,結果顯然是 65535
    short num2 = -1;
    printf("%hu\n", num2);  // 65535
    printf("%hu\n", 0b1111111111111111);  // 65535

    // 32 位整數(shù)也是如此
    int num3 = -1;
    // 2 的 32 次方減 1,結果是 4294967295
    printf("%u\n", num3);  // 4294967295
    return 0;
}

總結,對于一個有符號整數(shù)來說:

  • 如果是正數(shù)(符號位是 0),它的原碼、反碼、補碼是一致的。
  • 如果是負數(shù)(符號位是 1),反碼等于原碼的符號位不變、其它位取反,補碼等于反碼加 1;或者反碼等于補碼的符號位不變、其它位取反,原碼等于反碼加 1。

計算機存儲和運算使用的都是補碼,但展示的是原碼。

現(xiàn)在回到開頭的問題了,-1155459666 是怎么變成 3139507630 的。

圖片圖片

還是那句話,不看你怎么存,就看你怎么讀,反正存儲的就是這一坨二進制。如果以有符號格式讀取,最高位是符號位,結果就是 -1155459666;以無符號格式讀取,最高位也是有效位,結果就是 3139507630。

from ctypes import c_int, c_uint

print(c_int(-1155459666).value)
"""
-1155459666
"""
print(c_uint(-1155459666).value)
"""
3139507630
"""
print(0b10111011_00100001_00010101_10101110)
"""
3139507630
"""

那么問題來了,為什么要整出補碼這個東西出來呢?很好理解,有了補碼,加法和減法可以共用一套邏輯,無論是 a + b 還是 a - b,底層的運算邏輯是相同的。

最后再來解釋一下,為什么有符號八位整數(shù)的最大值是 127,最小值是 -128。

圖片圖片

兩個整數(shù) a 和 b,首先 a 的值肯定是 0,但問題是 b 的值是多少?難道是 -0 嗎?如果不考慮 0,那么有符號八位整數(shù)能表達的正數(shù)范圍是 1 ~ 127,負數(shù)范圍是 -1 ~ -127,然后還剩下兩個 0。于是讓 00000000 表示 0,讓 10000000 表示 -128。

圖片圖片

不管是多少位的有符號整數(shù),它的最小值的絕對值一定比最大值多 1,因此八位整數(shù)的最小值是 -128,最大值是 127。

事實上 10000000 表示 -128 有些人為規(guī)定的意思,但它確保了數(shù)字范圍的對稱性,并允許有效地利用二進制位來表達整數(shù)。

以上就是整數(shù)在底層的存儲方式,以及原碼、反碼、補碼之間的關系。

責任編輯:武曉燕 來源: 古明地覺的編程教室
相關推薦

2019-07-17 08:41:42

Java補碼反碼

2020-08-31 14:56:24

補碼存儲數(shù)據(jù)

2021-05-25 05:26:46

原碼反碼補碼

2017-03-16 15:28:20

人工智能視覺識別

2021-02-01 06:41:47

流水線計算機隊列

2021-10-29 11:30:31

補碼二進制反碼

2017-07-14 15:40:28

2023-07-07 10:53:08

2011-10-17 09:50:38

編程

2023-07-13 11:48:18

量子技術量子計算機

2021-02-03 05:25:39

存儲層次化代碼

2016-01-22 11:09:40

計算機圖形學虛擬現(xiàn)實三維建模

2023-09-04 15:15:17

計算機視覺人工智能

2015-09-30 11:22:19

計算機大數(shù)據(jù)

2023-10-11 18:30:39

Web系統(tǒng)程序

2021-03-12 18:26:27

云計算邊緣計算硬件

2023-09-20 16:31:03

人工智能

2018-08-24 10:35:49

物理內(nèi)存存儲

2024-03-28 11:32:38

計算機網(wǎng)絡集線器連接設備

2023-11-06 01:10:47

點贊
收藏

51CTO技術棧公眾號