Sorry, your browser cannot access this site
This page requires browser support (enable) JavaScript
Learn more >

负整数的二进制表示是理解计算机如何存储和处理负数的基石。主要有三种表示方法,其中最常用的是补码

1. 原码

规则:最高位表示符号位(0为正,1为负),其余位表示数值的绝对值。

示例(8位表示)

1
2
+5: 0000 0101
-5: 1000 0101

问题

  • +0 (0000 0000) 和 -0 (1000 0000) 两种零
  • 加减运算复杂,需要判断符号位

2. 反码

规则

  • 正数:与原码相同
  • 负数:符号位为1,数值位按位取反

示例(8位表示)

1
2
+5: 0000 0101
-5: 1111 1010 (5的原码 0000 0101 取反)

问题

  • 仍然存在 +0 (0000 0000) 和 -0 (1111 1111)
  • 运算仍不够方便

3. 补码 ⭐(现代计算机标准)

这是现代计算机普遍使用的方法。

3.1. 补码的规则

对于正数:与原码相同

1
+5: 0000 0101

对于负数:有两种计算方法:

方法一:取反加一

  1. 写出对应正数的二进制
  2. 按位取反(0变1,1变0)
  3. 结果加1

方法二:用 2ⁿ 减去绝对值

1
负数的补码 = 2ⁿ - |负数|

其中 n 是位数(8位、16位、32位、64位)

3.2. 示例:求 -5 的 8位补码

方法一:取反加一

1
2
3
+5:     0000 0101
取反: 1111 1010
加1: 1111 1011 ← -5的补码

方法二:公式计算

1
2
2⁸ - 5 = 256 - 5 = 251
251的二进制: 1111 1011

验证:1111 1011 就是 -5 的补码表示。

3.3. 更多例子(8位表示)

十进制 二进制(补码) 计算过程
+7 0000 0111 直接表示
+1 0000 0001 直接表示
0 0000 0000 直接表示
-1 1111 1111 0000 0001 → 1111 1110 → 1111 1111
-2 1111 1110 0000 0010 → 1111 1101 → 1111 1110
-5 1111 1011 0000 0101 → 1111 1010 → 1111 1011
-128 1000 0000 特殊值(8位最小负数)

4. 补码的优势

补码成为标准的原因:

4.1. 优势1:统一的加减法

减法可以转换为加法

1
10 - 5 = 10 + (-5)

在8位系统中:

1
2
3
10:     0000 1010
-5: 1111 1011
相加: 1 0000 0101 = 5 ✓ (忽略进位)

4.2. 优势2:唯一的零

只有 0000 0000 表示零,没有负零。

4.3. 优势3:自然的溢出行为

1
2
3
// 8位有符号整数的溢出
127 + 1 = -128 // 0111 1111 + 1 = 1000 0000
-128 - 1 = 127 // 1000 0000 - 1 = 0111 1111

4.4. 优势4:范围对称且连续

对于 n 位有符号整数:

  • 范围:-2^(n-1)2^(n-1)-1
  • 8位:-128 到 127
  • 16位:-32768 到 32767
  • 32位:-2147483648 到 2147483647

5. 快速识别补码表示的负数

规则:最高位为1的数就是负数。

快速计算负数值:看到补码表示的负数,想要知道它的十进制值:

  1. 减1
  2. 取反
  3. 得到正数值,加上负号

示例

1
2
3
4
看到: 1111 1011  (这是-5的补码)
减1: 1111 1010
取反: 0000 0101 = 5
结果: -5

6. C/C++ 中的验证代码

Demo1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <iostream>
#include <bitset>
using namespace std;

void print_binary_details(int num) {
cout << "十进制: " << num << endl;
cout << "二进制: " << bitset<8>(num) << endl;
cout << "十六进制: 0x" << hex << (num & 0xFF) << dec << endl;
cout << "---" << endl;
}

int main() {
// 测试正数和负数
print_binary_details(5);
print_binary_details(-5);
print_binary_details(0);
print_binary_details(-1);
print_binary_details(127);
print_binary_details(-128);

// 验证补码的加法特性
cout << "验证 10 + (-5) = 5:" << endl;
int a = 10, b = -5;
int result = a + b;
cout << a << " + " << b << " = " << result << endl;
cout << "10的二进制: " << bitset<8>(a) << endl;
cout << "-5的二进制: " << bitset<8>(b) << endl;
cout << "结果的二进制: " << bitset<8>(result) << endl;

return 0;
}

输出示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
十进制: 5
二进制: 00000101
十六进制: 0x5
---
十进制: -5
二进制: 11111011
十六进制: 0xfb
---
十进制: 0
二进制: 00000000
十六进制: 0x0
---
十进制: -1
二进制: 11111111
十六进制: 0xff
---

Demo2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <bitset>
#include <cstdint>
#include <iostream>

int main()
{
int8_t a = 127;
std::cout << "a: " << (int)a << ", bit:" << std::bitset<8>(a) << std::endl;
int8_t b = -127;
std::cout << "b: " << (int)b << ", bit:" << std::bitset<8>(b) << std::endl;
int8_t c = a + 1;
std::cout << "c: " << (int)c << ", bit:" << std::bitset<8>(c) << std::endl;
c >>= 2;
std::cout << "c: " << (int)c << ", bit:" << std::bitset<8>(c) << std::endl;
int8_t d = -5;
std::cout << "d: " << (int)d << ", bit:" << std::bitset<8>(d) << std::endl;
d <<= 2;
std::cout << "d: " << (int)d << ", bit:" << std::bitset<8>(d) << std::endl;
int8_t e = -1;
std::cout << "e: " << (int)e << ", bit:" << std::bitset<8>(e) << std::endl;
e >>= 2;
std::cout << "e: " << (int)e << ", bit:" << std::bitset<8>(e) << std::endl;

return 0;
}

输出示例

1
2
3
4
5
6
7
8
a: 127, bit:01111111
b: -127, bit:10000001
c: -128, bit:10000000
c: -32, bit:11100000
d: -5, bit:11111011
d: -20, bit:11101100
e: -1, bit:11111111
e: -1, bit:11111111

7. 重要总结

  1. 现代计算机统一使用补码表示有符号整数
  2. 最高位是符号位:0表示正数,1表示负数
  3. 补码计算:正数直接表示,负数 = 对应正数取反加1
  4. 优势:统一的加减运算、唯一的零、连续的范围
  5. 范围:n位有符号整数的范围是 -2^(n-1)2^(n-1)-1

理解补码对于进行位运算、处理溢出、优化性能等都至关重要!

评论