十进制与二进制的基本原理
十进制整数(如 5623)的含义可直观地表示为 (5 × 1000) + (6 × 100) + (2 × 10) + (3 × 1)。由于十进制共有 10 个数码,每向左一位,权值便乘以 10。
二进制数的原理完全相同,只因仅有 0 和 1 两个数码,故每向左一位,权值乘以 2。为方便阅读,常将二进制每 4 位分组书写(如 1101 0101),类似十进制中的千位分隔符。
下表列出 0–15 的十进制与二进制对应关系:
十进制值 | 二进制值 |
---|---|
0 | 0 |
1 | 1 |
2 | 10 |
3 | 11 |
4 | 100 |
5 | 101 |
6 | 110 |
7 | 111 |
8 | 1000 |
9 | 1001 |
10 | 1010 |
11 | 1011 |
12 | 1100 |
13 | 1101 |
14 | 1110 |
15 | 1111 |
一、二进制转十进制
以下示例均假设为无符号整数。
以 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。
表格化过程:
二进制位 | 0 | 1 | 0 | 1 | 1 | 1 | 1 | 0 |
---|---|---|---|---|---|---|---|---|
位权 | 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 |
乘积 | 0 | 64 | 0 | 16 | 8 | 4 | 2 | 0 |
合计 | 94 |
同理,1001 0111:
二进制位 | 1 | 0 | 0 | 1 | 0 | 1 | 1 | 1 |
---|---|---|---|---|---|---|---|---|
位权 | 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 |
乘积 | 128 | 0 | 0 | 16 | 0 | 4 | 2 | 1 |
合计 | 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。
表格化:
二进制位 | 1 | 0 | 0 | 1 | 0 | 1 | 0 | 0 |
---|---|---|---|---|---|---|---|---|
位权 | 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 |
乘积 | 128 | 0 | 0 | 16 | 0 | 4 | 0 | 0 |
合计 | 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
- 转为十进制后取负。
示例: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 通常被视为字符而非整型,直接输入输出可能产生意外行为。