Skip to content

O.4 - 二进制和十进制转换

Key Takeaway

考虑一个普通的十进制数,比如 5623。我们直观地理解这些数字的意思是 (5 * 1000) + (6 * 100) + (2 * 10) + (3 * 1)。因为有 10 个十进制数,所以左边每个后续数字的值都会增加 10 倍。

二进制数的工作方式相同,只是因为只有 2 个二进制数字(0 和 1),每个数字的值增加 2 倍。就像逗号通常用于使大十进制数易于阅读(例如1,427,435),我们经常以 4 位为一组编写二进制数,以便于阅读(例如 1101 0101)。

下表以十进制和二进制计数到 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 位(1 字节)二进制数 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。

这是表格格式的相同过程。我们将每个二进制数字乘以其数字值(由其位置确定)。将所有这些值加起来就是总数。

将 0101 1110 转换为十进制:

二进制数字 0 1 0 1 1 1 1 0
* 数字值 128 64 32 16 8 4 2 1
= 总计 (94) 0 64 0 16 8 4 2 0

让我们将 1001 0111 转换为十进制:

二进制数字 1 0 0 1 0 1 1 1
* 数字值 128 64 32 16 8 4 2 1
= 总计 (151) 128 0 0 16 0 4 2 1

1001 0111 二进制 = 十进制的 151。

这可以很容易地扩展到 16 位或 32 位二进制数,只需添加更多列即可。请注意,最简单的方法是从右端开始,然后向左移动,边走边将数字值乘以 2。

十进制转二进制的方法一

从十进制转换为二进制有点棘手,但仍然非常简单。有两种好方法可以做到这一点。

第一种方法是连续除以 2,然后记下余数。二进制数是在余数的末尾构造的,从下到上。

将 148 从十进制转换为二进制(使用 r 表示余数):

148 / 2 = 74 r0 74 / 2 = 37 r0 37 / 2 = 18 r1 18 / 2 = 9 r0 9 / 2 = 4 r1 4 / 2 = 2 r0 2 / 2 = 1 r0 1 / 2 = 0 r1

从下往上写出所有余数:1001 0100

148 十进制 = 1001 0100 二进制。

您可以通过将二进制转换回十进制来验证此答案:

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

十进制转二进制的方法二

第二种方法涉及逆向计算每个位必须是什么。对于较小的二进制数,此方法可能更容易。

再次考虑十进制数 148。小于148的2的最大次方是多少?128,所以我们将从那里开始。

是 148 >= 128 吗?是的,所以 128 位必须是 1. 148 - 128 = 20,这意味着我们需要再找到值 20 的位。 是 20 >= 64 吗?不,所以64位必须是0。20 >=32吗?不是,所以32位一定是0。20 >= 16吗?是的,所以 16 位必须是 1. 20 - 16 = 4,这意味着我们需要找到更多的 4 位。

是 4 >= 8 吗?不是,所以8位一定是0。 是4 >= 4吗?是的,所以第 4 位必须是 1。4 - 4 = 0,这意味着所有其余位必须是 0。

148 = (1 * 128) + (0 * 64) + (0 * 32) + (1 * 16) + (0 * 8) + (1 * 4) + (0 * 2) + (0 * 1) = 1001 0100

表格形式:

二进制数 1 0 0 1 0 1 0 0
* 数字值 128 64 32 16 8 4 2 1
= 总计 (148) 128 0 0 16 0 4 0 0

另一个例子

让我们使用方法 1 将 117 转换为二进制:

117 / 2 = 58 r1 58 / 2 = 29 r0 29 / 2 = 14 r1 14 / 2 = 7 r0 7 / 2 = 3 r1 3 / 2 = 1 r1 1 / 2 = 0 r1

从下往上的余数构造数,117 = 111 0101 二进制

并使用方法2:

2 小于 117 的最大次方是 64。

是 117 >= 64 吗?是的,所以 64 位必须是 1。117 - 64 = 53。53 >= 32 吗?是的,所以 32 位必须是 1。53 - 32 = 21。21 >= 16 吗?是的,所以 16 位必须是 1。 21 - 16 = 5。

5 >= 8 吗?不是,所以8位一定是0。 是5 >= 4吗?是的,所以第 4 位必须是 1。5 - 4 = 1。1 >= 2?不是,所以2位一定是0。 是1 >= 1吗?是的,所以 1 位必须是 1。

117 十进制 = 111 0101 二进制。

相加二进制数

在某些情况下(稍后我们会看到),能够将两个二进制数相加是很有用的。相加二进制数出奇地容易(甚至可能比添加十进制数更容易),尽管一开始它可能看起来很奇怪,因为您不习惯它。

考虑两个小的二进制数: 0110(十进制为 6)+ 0111(十进制为 7)

让我们添加这些。首先,像上面一样将它们排成一行。然后,从右向左开始,我们将每一列数字相加,就像我们在十进制数中所做的那样。但是,由于二进制数字只能是 0 或 1,所以只有 4 种可能:

  • 0 + 0 = 0
  • 0 + 1 = 1
  • 1 + 0 = 1
  • 1 + 1 = 0,将 1 移至下一列

让我们做第一列:

1
2
3
4
0110(十进制为 6)+
0111(十进制为 7)
----
   1

0 + 1 = 1。简单。

第二栏:

1
2
3
4
5
 1
0110(十进制为 6)+
0111(十进制为 7)
----
  01

1 + 1 = 0,带一个进位到下一列

第三栏:

1
2
3
4
5
11
0110(十进制为 6)+
0111(十进制为 7)
----
 101

这个有点棘手。通常情况下,1 + 1 = 0,带一个进位到下一列。但是,我们已经从上一列中携带了一个 1,因此我们需要加 1。因此,我们在这一列中得到一个 1,并将 1 带入下一列

最后一栏:

1
2
3
4
5
11
0110(十进制为 6)+
0111(十进制为 7)
----
1101

0 + 0 = 0,但有一个进位的 1,所以我们加 1。1101 = 十进制的 13。

现在,我们如何给任何给定的二进制数(例如 1011 0011)加 1?同上,只是最下面的数是二进制1。

1
2
3
4
5
       1个(进位柱)
1011 0011(原始二进制数)
0000 0001(二进制为 1)
---------
1011 0100

有符号数和补码

在上面的示例中,我们只处理了无符号整数。在本节中,我们将了解如何处理有符号数(可以为负数)。

有符号整数通常使用称为二进制补码的方法存储。在二进制补码中,最左边(最高有效位)的位用作符号位。符号位 0 表示数字为正数,符号位 1 表示数字为负数。

正符号数与无符号正数一样以二进制表示(符号位设置为 0)。

负符号数以二进制表示为正数的按位取反加 1。

十进制转二进制(二进制补码)

例如,这是我们如何用二进制二进制补码表示 -5:

首先我们找出 5 的二进制表示:0000 0101 然后我们反转所有位:1111 1010 然后我们添加 1:1111 1011

将 -76 转换为二进制:

二进制正 76:0100 1100 反转所有位:1011 0011 加 1:1011 0100

为什么要加1?考虑数字 0。如果将负值简单地表示为正数的倒数,则 0 将有两种表示形式:0000 0000(正零)和 1111 1111(负零)。通过加 1,1111 1111 有意溢出并变成 0000 0000。这可以防止 0 有两种表示形式,并简化了一些用负数进行算术运算所需的内部逻辑。

将二进制(二进制补码)转换为十进制

要将二进制补码转换回十进制,首先要查看符号位。

如果符号位为 0,只需按照上面无符号数所示的方式转换数字。

如果符号位是1,那么我们把位取反,加1,然后转成十进制,然后让那个十进制数变成负数(因为符号位本来就是负数)。

例如,要将 1001 1110 从二进制补码转换为十进制数: 给定:1001 1110 反转位:0110 0001 加 1:0110 0010 转换为十进制:(0 * 128) + (1 * 64) + (1 * 32 ) + (0 * 16) + (0 * 8) + (0 * 4) + (1 * 2) + (0 * 1) = 64 + 32 + 2 = 98 由于原始符号位为负,所以最后的值是-98。

为什么类型很重要

考虑二进制值 1011 0100。这代表什么值?你可能会说 180,如果这是一个标准的无符号二进制数,你就是对的。

但是,如果使用二进制补码存储此值,则它将是 -76。

如果该值以其他方式编码,则它可能完全不同。

那么 C++ 是如何知道将包含二进制 1011 0100 的变量打印为 180 还是 -76 呢?

如果章节标题没有透露,这就是类型发挥作用的地方。变量的类型决定了变量的值如何编码为二进制,以及如何解码回一个值。因此,如果变量类型是无符号整数,它会知道 1011 0100 是标准二进制,应该打印为 180。如果变量是有符号整数,它会知道 1011 0100 是使用二进制补码编码的(现在保证为C++20 的),并且应该打印为 -76

如何将浮点数从二进制转换为二进制?

浮点数如何从二进制转换为二进制要复杂得多,而且您可能永远都不需要知道。但是,如果您很好奇,请访问此站点,该站点很好地详细解释了该主题。