C++整数在二进制与十进制之间的转换详解(含补码与加法)

十进制与二进制的基本原理

十进制整数(如 5623)的含义可直观地表示为 (5 × 1000) + (6 × 100) + (2 × 10) + (3 × 1)。由于十进制共有 10 个数码,每向左一位,权值便乘以 10。

二进制数的原理完全相同,只因仅有 0 和 1 两个数码,故每向左一位,权值乘以 2。为方便阅读,常将二进制每 4 位分组书写(如 1101 0101),类似十进制中的千位分隔符。

下表列出 0–15 的十进制与二进制对应关系:

十进制值二进制值
00
11
210
311
4100
5101
6110
7111
81000
91001
101010
111011
121100
131101
141110
151111

一、二进制转十进制

以下示例均假设为无符号整数。

以 8 位二进制 0101 1110 为例:

0101 1110 = (0×128) + (1×64) + (0×32) + (1×16) + (1×8) + (1×4) + (1×2) + (0×1)
求和得:64 + 16 + 8 + 4 + 2 = 94。

表格化过程:

二进制位01011110
位权1286432168421
乘积0640168420
合计94

同理,1001 0111:

二进制位10010111
位权1286432168421
乘积12800160421
合计151

该方法可自然扩展至 16 位或 32 位,只需继续向左追加位权(×2 递增)。从右往左计算最为方便。

二、十进制转二进制

有三种常用方法。

方法 1:连续除 2 取余法

将十进制数不断除以 2,记录余数,最后自下而上读取余数即为二进制。

以 148 为例:

148 ÷ 2 = 74 余 0
74 ÷ 2 = 37 余 0
37 ÷ 2 = 18 余 1
18 ÷ 2 = 9  余 0
9  ÷ 2 = 4  余 1
4  ÷ 2 = 2  余 0
2  ÷ 2 = 1  余 0
1  ÷ 2 = 0  余 1

从下往上读:1001 0100,即 148 的二进制形式。

验证:

(1×128)+(0×64)+(0×32)+(1×16)+(0×8)+(1×4)+(0×2)+(0×1)=148。

此方法人工友好,但机器实现需额外缓存余数。

方法 2:递减位权法

从最高有效位权开始,依次判断是否需要该位。

仍以 148 为例,小于 148 的最大 2 的幂为 128:

148 ≥ 128 → 128 位为 1,剩余 20
20 < 64 → 64 位为 0
20 < 32 → 32 位为 0
20 ≥ 16 → 16 位为 1,剩余 4
4 < 8 → 8 位为 0
4 ≥ 4 → 4 位为 1,剩余 0
0 < 2 → 2 位为 0
0 < 1 → 1 位为 0

结果:1001 0100。

表格化:

二进制位10010100
位权1286432168421
乘积12800160400
合计148

方法 3:整除位权法(变体)

同样以 148 为例,对各位权整除后看奇偶:

148 / 128 = 1(奇)→ 128 位 1
148 / 64  = 2(偶)→ 64 位 0
148 / 32  = 4(偶)→ 32 位 0
148 / 16  = 9(奇)→ 16 位 1
148 / 8   = 18(偶)→ 8 位 0
148 / 4   = 37(奇)→ 4 位 1
148 / 2   = 74(偶)→ 2 位 0
148 / 1   = 148(偶)→ 1 位 0

同样得到 1001 0100。

人工计算量大,效率低,但代码实现无需条件分支。

再举一例:117

方法 1:

117 ÷ 2 = 58 余 1
58 ÷ 2 = 29 余 0
29 ÷ 2 = 14 余 1
14 ÷ 2 = 7  余 0
7 ÷ 2 = 3   余 1
3 ÷ 2 = 1   余 1
1 ÷ 2 = 0   余 1

自下而上:111 0101。

方法 2:

最大 2 的幂 ≤ 117 为 64 → 1,剩余 53
53 ≥ 32 → 1,剩余 21
21 ≥ 16 → 1,剩余 5
5 < 8 → 0
5 ≥ 4 → 1,剩余 1
1 < 2 → 0
1 ≥ 1 → 1

结果:111 0101。

三、二进制加法

在某些场景下需要手工或程序实现二进制加法。规则与十进制类似,但仅涉及 0 和 1。

示例:

0110 (6) + 0111 (7)

从右往左逐列相加:

0+1=1
1+1=0 并进位 1
1+1+进位 1=1 并进位 1
0+0+进位 1=1

结果为 1101 (13)。

若需对某二进制数加 1,只需设加数为 0000 0001,按同样规则即可。

四、有符号数与补码

前述示例均为无符号整数。本节讨论负数表示方法——补码(two’s complement)。

补码规则:

  • 最高位为符号位:0 表示非负,1 表示负。
  • 正数编码与无符号相同。
  • 负数编码为对应正数的按位取反再加 1。

示例:-5 的 8 位补码

1. 5 → 0000 0101
2. 取反 → 1111 1010
3. 加 1 → 1111 1011

-76 的 8 位补码:

1. 76 → 0100 1100
2. 取反 → 1011 0011
3. 加 1 → 1011 0100

加 1 的原因:若仅取反而得“反码”,则 0 会出现 0000 0000 和 1111 1111 两种表示。补码通过加 1 使得 1111 1111 溢出为 0000 0000,从而唯一表示 0,并简化负数运算。

补码转十进制:

  • 若符号位为 0,直接按无符号规则转换。
  • 若符号位为 1:
    1. 取反
    2. 加 1
    3. 转为十进制后取负。

示例:1001 1110(补码)

取反 → 0110 0001
加 1 → 0110 0010 → 98
符号位为 1,故结果为 -98。

手工速算:最高位权为负,其余为正。

1001 1110 = (1×-128) + (0×64) + (0×32) + (1×16) + (1×8) + (1×4) + (1×2) + (0×1) = -128 + 16 + 8 + 4 + 2 = -98。

五、类型的重要性

同一二进制 1011 0100,若视为无符号则为 180;若视为补码有符号则为 -76。
C++ 通过变量类型决定编解码方式:

  • 若为 unsigned,解码为 180;
  • 若为 signed,解码为 -76(C++20 起补码已标准化)。

六、浮点数的二进制转换

浮点数的二进制表示规则更复杂,通常无需掌握。如需了解,可参考相关资料。

C++二进制与十进制转换测验

问题 1

将 0100 1101 转为十进制。

问题 2

用方法 1 与方法 2 将 93 转为 8 位无符号二进制。

问题 3

将 -93 转为 8 位补码有符号二进制。

问题 4

将 1010 0010 转为无符号十进制。

问题 5

将 1010 0010 转为补码有符号十进制。

问题 6

编写程序,要求用户输入 0–255 之间的整数,并以 #### #### 形式输出 8 位二进制。不得使用位运算符,不得使用 std::bitset。
提示:std::uint8_t 通常被视为字符而非整型,直接输入输出可能产生意外行为。

关注公众号,回复"cpp-tutorial"

可领取价值199元的C++学习资料

公众号二维码

扫描上方二维码或搜索"cpp-tutorial"