并非所有数字都有原码、反码、补码三种形式**。这三种编码仅适用于**有符号整数**
(如 `int`、`int8_t`),且不同编码的表示范围和规则不同。且补码是唯一实际使用的标准。
– **无符号整数**(如 `unsigned int`)只有原码(即直接二进制表示),没有反码和补码的概念。
– **浮点数**(如 `float`、`double`)使用 **IEEE 754 标准**,与这三种编码无关。
原码、反码、补码的定义与关系
原码是数值的二进制表示形式,最高位为符号位(0表示正数,1表示负数),其余位表示数值的绝对值。
反码是在原码的基础上,正数的反码与原码相同;负数的反码是符号位不变,其余位按位取反。
补码是在反码的基础上加1(正数的补码与原码相同)。补码是现代计算机中表示有符号整数的标准方式,因其解决了原码和反码中“零的表示不唯一”的问题,并简化了算术运算。
#### ** 举例说明 **
1. **原码(Sign-Magnitude)**
– **定义**:最高位表示符号(`0`为正,`1`为负),其余位表示数值绝对值。
– **示例**:
– `+5`:`0 0000101`
– `-5`:`1 0000101`
– **问题**:存在 `+0`(`0 0000000`)和 `-0`(`1 0000000`),导致运算复杂。
2. **反码(Ones' Complement)**
– **定义**:正数的反码与原码相同(直接二进制表示,符号位为 `0`);
负数的反码是对原码**按位取反**(符号位不变)。
– **示例**:
– `+5`:`0 0000101`
– `-5`:`1 1111010`
– **问题**:仍存在 `+0` 和 `-0`,且加减法需处理进位。
– **反码是计算机历史的过渡方案**,现已被补码取代。
– **核心规则**:正数不变,负数按位取反。
– **唯一价值**:帮助理解补码的设计逻辑(补码 = 反码 + 1)。
3. **补码(Two's Complement)**
– **定义**:正数与原码相同;负数是反码加 1(符号位参与运算)。
– **示例**:
– `+5`:`0 0000101`
– `-5`:`1 1111011`
– **优点**:消除 `-0`,统一加减法,硬件实现简单。
特殊数字的编码表现
零的表示:
- 原码中,零有两种表示形式:+0(如00000000)和-0(如10000000)。
- 反码中,零同样有两种形式:+0(00000000)和-0(11111111)。
- 补码中,零只有一种形式(00000000),-0的补码与+0相同。
三者转换关系
特点与优缺点
- 原码:直观,但存在+0和-0的歧义,加减运算复杂。
- 反码:解决了加减运算问题,但仍存在零的歧义。
- 补码:唯一表示零,加减运算统一,硬件实现简单。
– **原码和反码的淘汰**:
原码和反码因存在 `±0`、运算复杂等问题,**仅在历史早期或特定场景中出现**,现代通用 CPU 已不再使用。
#### **2. 为什么补码成为标准?**
| 特性 | **补码** | **原码/反码** |
|———————-|————————————|———————————|
| 零的表示** | 唯一(`000…0`) | 存在 `+0` 和 `-0` |
| 加减法统一性 | 直接硬件加法器即可处理 | 需额外电路处理符号和进位 |
| **硬件复杂度** | 简单高效 | 复杂 |
| **范围对称性** | 对称(8 位:-128 ~ +127) | 不对称(8 位原码:-127 到 +127) |
#### **6. 总结**
– **计算机中所有有符号整数**(如 `int`、`int32_t`)**均使用补码**。
– **原码和反码已退出实际应用**,仅作为历史或理论存在。
– **浮点数**和**无符号整数**的编码与补码无关。
:除非在博物馆维护古董计算机,否则只需掌握补码!
对补码进行补充理解:
补码的计算方法
对于一个n位二进制数,补码的计算步骤如下:
正数的补码是其本身。例如,8位系统中+5的补码是00000101。
负数的补码是其绝对值的二进制表示取反(反码)后加1。例如,-5的补码计算过程:
-n与补码的关系
直接对n取负数(-n)并不等同于补码。补码是二进制表示形式,而-n是数学上的负数概念。补码
的生成需要具体的位数(如8位、16位)和二进制操作。
// 原码,反码,补码打印查看
/bit_proc_00_code_underdtand_01.cc
// 原码,反码,补码打印查看
// 输入一个整数,查看打印出来的原码,反码,和补码
#include <iostream>
#include <bitset>
using namespace std;
// 打印原码,反码,补码,(使用位操作)
void print(int num)
{
// 原码
bitset<32> original;
if (num >= 0) {
original = bitset<32>(num);
} else {
original = bitset<32>(-num);
original.set(31, 1); // 设置符号位
}
// 反码
bitset<32> inverse;
if (num >= 0) {
inverse = original;
} else {
inverse = original;
for (int i = 0; i < 31; ++i) {
inverse.flip(i); // 除符号位外取反
}
}
// 补码
bitset<32> complement;
if (num >= 0) {
complement = original;
} else {
complement = inverse;
// 反码加1
bool carry = true;
for (int i = 0; i < 32 && carry; ++i) {
if (complement[i] == 0) {
complement.set(i, 1);
carry = false;
} else {
complement.set(i, 0);
}
}
}
cout << "数值: " << num << endl;
cout << "原码: " << original << endl;
cout << "反码: " << inverse << endl;
cout << "补码: " << complement << endl;
cout << "——————\\n" << endl;
}
int main()
{
int num = 0;
cout << "input num : ";
while (cin >> num) {
print(num);
cout << "input num : ";
}
return 0;
}
打印测试:

// 原码,反码,补码打印查看
/bit_proc_00_code_underdtand_02.cc
// 原码,反码,补码打印查看
// 输入一个整数,查看打印出来的原码,反码,和补码
#include <iostream>
#include <bitset>
using namespace std;
// 打印原码,反码,补码,(使用位操作)
void print(int num)
{
// 原码
bitset<32> original = bitset<32>(abs(num));
if (num < 0) original.set(31, 1);
// 反码
bitset<32> inverse = original;
if (num < 0) inverse ^= bitset<32>(0x7FFFFFFF);
// 补码(直接利用无符号转换)
bitset<32> complement = bitset<32>(static_cast<unsigned int>(num));
cout << "数值: " << num << endl;
cout << "原码: " << original << endl;
cout << "反码: " << inverse << endl;
cout << "补码: " << complement << endl;
cout << "——————\\n" << endl;
}
int main()
{
int num = 0;
cout << "input num : ";
while (cin >> num) {
print(num);
cout << "input num : ";
}
return 0;
}
测试

// 补码打印
/bit_proc_00_code_underdtand_03.cc
// 补码打印
#include <iostream>
#include <bitset>
using namespace std;
// ### 为什么 `n`,`-n` 可以直接表示其补码?
// #### 1. 计算机存储的本质
// 在计算机中,所有整数(无论正负)都以补码形式存储。因此:
// – `n`:直接输出时,`std::bitset<8>(n)` 会自动显示 `n` 的补码表示。
// – `-n`:计算时,计算机先求 `n` 的补码,再对其取反加 1 得到 `-n` 的补码,最后以补码形式存储结果。
// #### 2. 补码的对称性
// 补码的设计使得 `-n` 的补码 = `n` 的补码的“取反加 1”。
// – 硬件支持:CPU 的指令集直接支持补码的负数运算(如 `NEG` 指令)。
// – 编译器行为:`-n` 会被编译为对 `n` 的补码取反加 1 的操作。
// #### 总结
// – `n` 和 `-n` 的补码表示是计算机硬件的直接行为,无需手动转换。
// – 补码的数学性质:`-n` 的补码 = `~n + 1`,这是补码定义的核心。
// – 实际编程中:直接使用 `-n` 即可获得其补码,因为编译器会自动处理补码运算。
// **关键点**:
// 补码的统一表示让计算机能直接用硬件指令处理正负数,而程序员无需关心底层细节。
int main()
{
int n = 0;
cout << "input num : ";
while (cin >> n) {
std::cout << n << " 的补码: " << std::bitset<8>(n) << "\\n";
std::cout << n << " 的补码取反加1: " << std::bitset<8>(~n + 1) << "\\n";
std::cout << -n << " 的补码: " << std::bitset<8>(-n) << "\\n";
std::cout << "input num : ";
}
return 0;
}
测试

// 获取最低位的1
/bit_proc_00_code_underdtand_04.cc
// 获取最低位的1
#include <iostream>
#include <bitset>
void print(int freePos)
{
std::cout << " 初始值 freePos : " << std::bitset<8>(freePos) << " (" << freePos << ")\\n";
std::cout << " -freePos : " << std::bitset<8>(-freePos) << " (" << -freePos << ")\\n";
// 提取最低位的1
// int pos = freePos & (-freePos); 是一个位运算技巧,用于提取二进制数中最右边的1。
// -pos和pos仅在最低位的1及其右边的的位上相同,右边的位会变成0,左边的位全部相反。
// -freePos` 的补码表示**: 在计算机中,负数以补码存储,`-freePos` 等于 `~freePos + 1`。
// `freePos & -freePos` 会保留 `freePos` 最低位的 `1`,其他位清零。
int pos = freePos & (-freePos);
std::cout << " 最低位的1 : " << std::bitset<8>(pos) << " (" << pos << ")\\n";
// 移除已提取的1
freePos -= pos;
std::cout << "移除后的 freePos : " << std::bitset<8>(freePos) << " (" << freePos << ")\\n";
std::cout << "——————\\n" << std::endl;
}
int main()
{
int num = 0;
std::cout << "输入一个整数: ";
while (std::cin >> num) {
print(num);
std::cout << "输入一个整数: ";
}
return 0;
}
测试:




