C++ 编程/学习基础
大多数计算机系统使用二进制逻辑运行。计算机使用两个电压电平表示值,通常是 0V 表示逻辑 0,而 +3.3V 或 +5V 表示逻辑 1。这两个电压电平恰好表示两个不同的值,按照惯例,这些值是零和一。巧合的是,这两个值对应于二进制数系统使用的两个数字。由于计算机使用的逻辑电平与二进制数系统使用的两个数字之间存在对应关系,因此计算机采用二进制系统也就不足为奇了。
二进制数系统使用基数 2,它只包含数字0和1。
在美国和其他国家,每三位十进制数字用逗号分隔,使较大的数字更容易阅读。例如,123,456,789 比 123456789 更容易阅读。我们对二进制数也采用了类似的约定。为了使二进制数更易读,我们在小数点左侧的最低有效数字开始,每四位数字添加一个空格。例如,二进制值 1010111110110010 将写成1010 1111 1011 0010。
使用上面的示例1010 1111 1011 0010
- 最右侧的序列(0010)位于位号 0,其值为0。位号 0 称为最低有效位,或lsb
- 左侧的每个位都分配了下一个连续的位号。位 1、位 2等等...
- 最左侧的位(1010)通常称为最高有效位,或msb,其值为1。
我们通常将二进制数写成一系列位。不同位的大小有定义的边界
名称 | 大小(位) | 示例 |
---|---|---|
位 | 1 | 1 |
字节 | 4 | 0101 |
字节 | 8 | 0000 0101 |
字 | 16 | 0000 0000 0000 0101 |
双字 | 32 | 0000 0000 0000 0000 0000 0000 0000 0101 |
在任何进制中,我们可以添加任意数量的领先零而不会改变其值,但在二进制数系统中,添加领先零会将位调整到所需的大小。例如,我们可以将数字5表示为一个
位 101;
字节 0101;
字节 0000 0101;
字 0000 0000 0000 0101; 或
双字 0000 0000 0000 0000 0000 0000 0000 0101
- 字
字的边界可以定义为 16 位或处理器的地址总线大小。因此,字和双字不是固定大小,而是根据系统(具体取决于处理器)而有所不同。
对于 8085 和 8086 微处理器,字是一组 16 位。我们从位号 0 (b0) 到十五 (b15) 对字中的位进行编号,如下所示
b15 | b14 | b13 | b12 | b11 | b10 | b9 | b8 | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 |
请记住,b0是LSB,b15是msb,在引用字中的其他位时,请使用它们的位号。请注意,字正好包含两个字节。b0-b7构成低字节,b8-b15构成高字节。自然,字可以进一步细分为四个字节。字节零是低字节(b0-b4),字节三是字的高字节(b12-b15)。另外两个字节是“字节一”和“字节二”。
使用 16 位,你可以表示2^16或65,536个不同的值。这些值可能是范围为 0 => 65,535 的无符号数值、范围为 -32,768 => +32,767 的有符号数值,或任何不超过65,536个值的任何其他数据类型。字的三种主要用途是
- 16 位整型数据值
- 16 位内存地址
- 任何需要 16 位或更少位的进制
- 双字
双字就是两个字,所以双字量是 32 位。自然,这个双字可以细分为一个高字和一个低字,四个字节或八个字节。
双字可以表示各种不同的数据
- 范围为 0 => 4,294,967,295 的无符号双字
- 范围为 - 2,147,483,648 => +2,147,483,647 的有符号双字
- 32 位浮点数
- 任何需要 32 位或更少位的数据
从二进制数转换为十进制数非常容易。
例如,让我们分解二进制值1100 1010
数字 | 1 | 1 | 0 | 0 | 1 | 0 | 1 | 0 |
位号 | b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 |
基数 2 | 2^7 | 2^6 | 2^5 | 2^4 | 2^3 | 2^2 | 2^1 | 2^0 |
现在就像十进制系统一样,我们将每个数字乘以基数 2及其加权位置值,然后求和,如下所示
1(2^7) | 1(128) | 128 |
1(2^6) | 1(64) | 64 |
0(2^5) | 0(32) | 0 |
0(2^4) | 0(16) | 0 |
1(2^3) | 1(8) | 8 |
0(2^2) | 0(4) | 0 |
1(2^1) | 1(2) | 2 |
0(2^0) | 0(1) | 0 |
=202 |
从十进制转换为二进制稍微困难一些。
有两种方法,除以 2和减去加权位置值。
为此,我们将十进制数除以 2,如果余数是0,则写下0。如果余数是1,则写下1。重复此过程,直到商为0。
余数将表示十进制数的二进制等效值。余数值从最低有效数字写入最高有效数字。因此,每个新的余数值都写在之前的余数值左侧。
例如,考虑数字2671。
除法 | 商 | 余数 | 二进制数 |
2671 / 2 | 1335 | 1 | 1 |
1335 / 2 | 667 | 1 | 11 |
667 / 2 | 333 | 1 | 111 |
333 / 2 | 166 | 1 | 1111 |
166 / 2 | 83 | 0 | 0 1111 |
83 / 2 | 41 | 1 | 10 1111 |
41 / 2 | 20 | 1 | 110 1111 |
20 / 2 | 10 | 0 | 0110 1111 |
10 / 2 | 5 | 0 | 0 0110 1111 |
5 / 2 | 2 | 1 | 10 0110 1111 |
2 / 2 | 1 | 0 | 010 0110 1111 |
1 / 2 | 0 | 1 | 1010 0110 1111 |
从一个大于该数字的加权位置值开始。如果该数字小于加权值,则写下0并减去0。如果该数字大于加权值,则写下1,但要减去加权值。重复此过程,直到结果为0。
在执行减法时,数字将表示从最高有效位到最低有效位的十进制数的二进制等效值。因此,每个新数字都写到前一个数字的右边。
考虑相同的数字,2671
加权值 | 减法 | 余数 | 二进制数 |
2^12 = 4096 | 2671 - 0 | 2671 | 0 |
2^11 = 2048 | 2671 -2048 | 623 | 01 |
2^10 = 1024 | 623 - 0 | 623 | 010 |
2^9 = 512 | 623 - 512 | 111 | 0101 |
2^8 = 256 | 111 - 0 | 111 | 0 1010 |
2^7 = 128 | 111 - 0 | 111 | 01 0100 |
2^6 = 64 | 111 - 64 | 47 | 0 1010 01 |
2^5 = 32 | 47 - 32 | 15 | 0 1010 011 |
2^4 = 16 | 15 - 0 | 15 | 0 1010 0110 |
2^3 = 8 | 15 - 8 | 7 | 0 1010 0110 1 |
2^2 = 4 | 7 - 4 | 3 | 0 1010 0110 11 |
2^1 = 2 | 3 - 2 | 1 | 0 1010 0110 111 |
2^0 = 1 | 1 - 1 | 0 | 0 1010 0110 1111 |
虽然这曾经是一个流行的数制,特别是在数字设备公司 PDP/8 和其他旧的计算机系统中,但如今很少使用。八进制系统基于二进制系统,以 3 位为界。
八进制系统使用基数 8,它只包含数字 0,1,2,3,4,5,6 和 7(任何其他数字都会使数字成为无效的八进制数)。
- 八进制数字的二进制形式
八进制数字 | 二进制数 |
0 | 000 |
1 | 001 |
2 | 010 |
3 | 011 |
4 | 100 |
5 | 101 |
6 | 110 |
7 | 111 |
- 现在是每个八进制位置的加权值
8^6 | 8^5 | 8^4 | 8^3 | 8^2 | 8^1 | 8^0 |
262144 | 32768 | 4096 | 512 | 64 | 8 | 1 |
将二进制值转换为八进制数很容易。
首先,将二进制数从LSB到MSB分成 3 位的节,然后将 3 位的二进制数转换为它的八进制等效值。
让我们分解二进制值1010111110110010
3 位 | 001 | 010 | 111 | 110 | 110 | 010 |
MSB | LSB | |||||
八进制数字 | 1 | 2 | 7 | 6 | 6 | 2 |
从八进制数转换为二进制值也很容易。
将十进制数转换为它的 3 位二进制等效值,然后合并 3 位的节。
让我们以上面的八进制数127662为例,将其分解
八进制数字 | 3 位 |
1 | 001 |
2 | 010 |
7 | 111 |
6 | 110 |
6 | 110 |
2 | 010 |
这将产生二进制数001010111110110010,或者以更易读的格式表示为0000 1010 1111 1011 0010。
要将八进制转换为十进制,请将每个位置的值乘以其八进制权重,然后将每个值加起来。
同样,让我们以八进制值127662为例
1(8^5) | 1(32768) | 32768 |
2(8^4) | 2(4096) | 8192 |
7(8^3) | 7(512) | 3584 |
6(8^2) | 6(64) | 384 |
6(8^1) | 6(8) | 48 |
2(8^0) | 2(1) | 2 |
=44978 |
将十进制转换为八进制稍微困难一些。
将十进制转换为八进制的典型方法是重复除以 8。对于此方法,将十进制数除以 8,并将余数写在旁边作为最低有效位。通过将商除以 8 并写入余数,直到商为 0,继续此过程。在执行除法时,将表示十进制数的八进制等效值的余数从最低有效位(右边)开始写入,并将每个新数字写入到前一个数字的下一个更高有效位(左边)。考虑数字 44978。
除法 | 商 | 余数 | 八进制数 |
44978 / 8 | 5622 | 2 | 2 |
5622 / 8 | 702 | 6 | 62 |
702 / 8 | 87 | 6 | 662 |
87 / 8 | 10 | 7 | 7662 |
10 / 8 | 1 | 2 | 27662 |
1 / 8 | 0 | 1 | 127662 |
如您所见,我们又回到了原来的数字。
二进制系统的一个大问题是冗长。例如,表示值 202 需要 8 个二进制数字,而十进制版本只需要 3 个十进制数字。特别是对于较大的值,二进制数变得过于笨拙。十六进制记数系统解决了这些问题。
十六进制数非常紧凑,并且易于从十六进制转换为二进制,以及从二进制转换为十六进制。由于我们经常需要将十六进制数输入计算机系统,因此我们需要一种不同的机制来表示十六进制数,因为您无法输入下标来表示相关值的基数。
十六进制系统基于二进制系统,使用一个字节或 4 位为界。在汇编语言编程中,大多数汇编器要求十六进制数的第一个数字为0,并且我们在数字末尾放置一个H来表示数字基数。
十六进制数系使用基数 16,它只包含数字0到9以及字母A、B、C、D、E和F。
此表提供了从 0 到 16 的十进制值的所有信息,您可以将其用于将一种数制转换为任何其他数制。
十进制 | 十六进制 | 二进制 | 八进制 |
00 | 00H | 0000 | 00Q |
01 | 01H | 0001 | 01Q |
02 | 02H | 0010 | 02Q |
03 | 03H | 0011 | 03Q |
04 | 04H | 0100 | 04Q |
05 | 05H | 0101 | 05Q |
06 | 06H | 0110 | 06Q |
07 | 07H | 0111 | 07Q |
08 | 08H | 1000 | 10Q |
09 | 09H | 1001 | 11Q |
10 | 0AH | 1010 | 12Q |
11 | 0BH | 1011 | 13Q |
12 | 0CH | 1100 | 14Q |
13 | 0DH | 1101 | 15Q |
14 | 0EH | 1110 | 16Q |
15 | 0FH | 1111 | 17Q |
16 | 10H | 1 0000 | 20Q |
要将十六进制数转换为二进制数
1. 将十六进制数分解为每个单独的十六进制数字
2. 替换每个十六进制数字对应的二进制值
3. 每个二进制值从MSB(左边)开始到LSB(右边)写入
例如,要将0ABCDH转换为二进制值,只需根据上面的表格转换每个十六进制数字。
十六进制数字 | 二进制值 |
0 | 0000 |
A | 1010 |
B | 1011 |
C | 1100 |
D | 1101 |
- 0ABCDH = 0000 1010 1011 1100 1101
将二进制数转换为十六进制格式几乎同样容易。
例如,给定二进制数1011001010,第一步是在MSB位置添加两个零,使其包含 12 位。然后将二进制值分成 4 位一组,因此修改后的二进制值变为0010 1100 1010。然后我们在上面的表格中查找二进制值并替换相应的十六进制数字
0010 | 2 |
1100 | C |
1010 | A |
因此0010 1100 1010 = 2CA
另一个例子,1010111110110010 转换为 AFB2。
每个位置的加权值如下所示
16^0 | 1 |
16^1 | 16 |
16^2 | 256 |
16^3 | 4096 |
要将十六进制转换为十进制,请将每个位置的值乘以其加权值,然后加起来。使用上面的表格和前面的例子,0AFB2H,我们预计将获得十进制值44978。
A(16^3) | 10(4096) | 40960 |
F(16^2) | 15(256) | 3840 |
B(16^1) | 11(16) | 176 |
2(16^0) | 2(1) | 2 |
=44978 |
将十进制转换为十六进制稍微困难一些。典型方法是重复除以 16。
虽然我们也可以使用重复减去加权位置值,但这对于较大的十进制数而言更困难。
除法方法
将十进制数除以 16,并将余数写在旁边作为最低有效位。继续此过程,直到商为0。在执行除法时,将表示十进制数的十六进制等效值的余数从最低有效位(右边)开始写入,并将每个新数字写入到前一个数字的下一个更高有效位(左边)。考虑数字 44978。
除法 | 商 | 余数 | 十六进制数 |
44978 / 16 | 2811 | 2 | 2 |
2811 / 16 | 175 | 11 | B2 |
175 / 16 | 10 | 15 | FB2 |
10 / 16 | 0 | 10 | 0AFB2 |
- 44978 = 0AFB2
在 8085 程序中使用十六进制数时,汇编器通常要求最高有效位十六进制数字为 0,即使此数字位数超过寄存器的大小。这是汇编器要求,您的值将被正确地汇编。
像十进制数一样加法,但:
如果单个数字是 A 到 F,我们必须将其转换为十进制等效值(上面的表格中的值),然后加起来。
例如
求 D + C 的和
0DH = 13 以及 0CH = 12 所以;
13 + 12 = 25 因此;
D + C = 25 但是;
如果和大于或等于 16,我们将和替换为和减 16 并进位 1。
例如
25 - 16 = 9;然后
D + C = 19;最后
3) 如果和介于 10 到 15(十进制)之间,我们将用等效的十六进制数字替换和,例如
进位 | --> | 1 1 |
DF6D | ||
+ | 246C | |
溢出 | --> 1 | 03D9 |
二进制和十六进制加法的更多示例:
进位 | --> | 11111 | |
111011 | |||
+ | 100111 | ||
溢出 | --> | 1 | 100010 |
进位 | --> | 1 1 | |
11001 | |||
+ | 01101 | ||
溢出 | --> | 1 | 00110 |
1235 | ||
+ | 567A | |
无溢出 | --> | 68AF |
进位 | --> | 111 | |
A9876 | |||
+ | FDCA0 | ||
溢出 | --> | 1 | A7516 |
我们的十进制数制被称为位置数制,因为数字的值取决于数字的位置。例如,数字 123 与 321 不同,即使使用了相同的数字。其他古代数制使用额外的符号来表示更大的值,但在位置数制中,每个数字的值由它在整个数字中的位置决定。最低位值是右边的位置,每个连续的左边的位置具有更高的位值。最右边的位置代表“个位”列,下一个位置代表“十位”列,下一个位置代表“百位”等。因此,数字 123 代表 1 个百和 2 个十和 3 个一,而数字 321 代表 3 个百和 2 个十和 1 个一。
每个位置的值对应于数制基数的幂。因此,对于我们的十进制数制,它使用基数 10,位值对应于 10 的幂
10^0 | = 1 |
10^1 | = 10 |
10^2 | = 100 |
10^3 | = 1000 |
其他数制使用不同的基数。二进制数制使用基数 2,因此二进制数字的数字的位值对应于 2 的幂。
例如,二进制数 10011 的值是通过计算 该数字的每个二进制位 的位值来确定的
1 | 0 | 0 | 1 | 1 | 二进制数 |
(2^4) | (2^3) | (2^2) | (2^1) | (2^0) | 位值 |
因此,二进制数 10011 代表值
1 (2^4) | + 0(2^3) | + 0 (2^2) | + 1 (2^1) | +1 ( 2^0) |
= 16 | + 0 | + 0 | + 2 | + 1 |
= 19 |
相同的原理适用于任何进制。例如,数字 2132(以 5 为基) 对应于
2 | 1 | 3 | 2 | 以 5 为基的数字 |
(5^3) | (5^2) | (5^1) | (5^0 | 位值 |
因此,数字 2132(以 5 为基) 的值是
2(5^3) | +1(5^2) | +3(5^1) | +2(5^0) |
=2(125) | +1(25) | +3(5) | +2(1) |
= 250 | +25 | +15 | +2 |
= 292 |
为了将十进制数转换为不同的进制,我们必须能够用其他进制的幂来表示该数字。要将十进制数 100 转换为 4 进制,我们必须弄清楚如何将 100 表示为 4 的幂之和,例如
100= | 1(64) | + 2(16) | + 1(4) | + 0(1) |
= 1(4^3) | + 2(4^2) | + 1(4^1) | + 0(4^0) |
然后我们使用 4 的幂的系数来形成以 4 进制表示的数字
100 | = 1 | 2 | 1 | 0 | 4 进制 |
另一种方法是重复地将十进制数除以要转换到的进制,直到商为零。当数字被除时,余数 - 反向顺序 - 形成数字在其他进制中的数字。例如
将十进制数 82 转换为 6 进制
82/6 | = 13 余数 4 |
13/6 | = 2 余数 1 |
2/6 | = 0 余数 2 |
答案是通过反向顺序取余数 形成的:2 1 4(以 6 为基)
数制之间的转换示例
十进制 | 二进制 | 十六进制 |
255 | 1111 1111 | FF |
93 | 0101 1101 | 5D |
计算机算术是在存储在定长内存位置中的数据上执行的,通常为 8 位、16 位或 32 位。
操作定长数字会遇到特殊问题。数字 280(以 10 为基)大于最大 8 位数;这会导致二进制表示中超过 8 位的进位,以及十六进制表示中超过两位的进位。在使用定长数字进行算术运算时,这些进位可能会丢失。
十进制 | 二进制 | 十六进制 |
---|---|---|
201 | 11001001 | C9 |
+79 | +01001111 | +4F |
280 | 1 00011000 | 1 18 |
符号位- 使用一位表示符号,7 位表示数字。
示例:-1(在 8 位系统中)可以是 1000 0001(以 2 为基)
补码(在计算中最常使用)
示例:表示 -1(在 8 位系统中)的补码数字为 1111 1111(以 2 为基)
考虑自行车上的里程表数字:考虑自行车上的里程表数字
十进制示例里程表数字可用于带符号数字的加法和减法(补码)。- 2 + 998 + 3 + 003 + 1 1 001
在第二个示例中,正确的结果只是 +001;溢出在定长补码算术中被忽略。使用补码将减法视为加法,即 A - B = A + (-B) 重要提示:计算 -B 并相加比直接减法更容易。示例:- 005 + 995 + 003 + 997 + 008 1 992
请注意,995 和 997 以正常方式相加,溢出被忽略,结果为 992,它可以从补码(或里程表)系统转换回 -8,即正确答案。
signed 3-bit complement +3 003 +2 002 +1 001 0 000 -1 999 -2 998 -3 997 -4 996 -5 995 -6 994 -7 993 -8 992
十进制 补码 二进制
+127 01111111 +126 01111110 +125 01111101 ... ........ +2 00000010 +1 00000001 0 00000000 -1 11111111 -2 11111110 ... ........ -127 10000001 -128 10000000
在 8 位定长补码数制中,有 256 个数字。为什么这些数字被称为补码?M - N = M + (-N),其中 -N 是 N 的补码。
示例:十进制
+ 1 = 00000001 - 1 = + 11111111 0 = 1 00000000
它不等于 2^8 或 256;忽略溢出,正确答案为零。现在我们需要一种简单的方法来执行补码运算。
示例:-27(以 10 为基)在补码 8 位表示法中的表示是什么?
2^8 - 1 11111111
- 27 - 00011011
11100100 corresponds to flipping all the bits; also known as 1's complement add 1 + 00000001 result 11100101 -27 in 2's complement representation
这种方法是必要的,因为:1. 计算机中存储的数字的定长特性 2. 实现快速加法器比实现加法器和减法器更有效率 ________________________________________ 补码数字运算示例 补码形式的加法和减法 • 加法:要计算 N1 + N2,将 N1 加到 N2 • 减法:要计算 N1 - N2,将 N1 加到 -N2 示例:十进制 二进制 十六进制
11 = 00001011 = 000B + 21 = + 00010101 = + 0015 32 = 00100000 = 0020
21 = 00010101 = 0015 - 11 = + 11110101 = + FFF5 10 = 00001010 = 000A
11 = 00001011 = 000B - 21 = + 11101011 = + FFEB - 10 = 11110110 = FFF6
- 11 = 11110101 = FFF5 - 21 = + 11101011 = + FFEB - 32 = 1 11100000 = FFE0
我们如何得到 -11 和 -21 的补码
11 00001011
~11 - 11110100 1 的补码 + 1 + 00000001 加 1 -11 11110101 补码表示
算法 1. 存储 N。2. 获取 ~N,即 N 的 1 的补码,方法是在数字的二进制表示中(逐位)将每个 0 替换为 1,反之亦然。3. 加 1 并忽略第八位后的任何进位。注意:此算法在十六进制中有效,方法是将每个数字 x 替换为其十六进制补码,即 15 - x。示例:11 的十六进制等效值为 $000B;然后其十六进制补码为 $FFF4,其中每个数字都计算为 $F - x。将 $FFF4 加 1 会得到 $FFF5,即 11 的补码。(在数字前面使用美元符号 ($) 表示它是 16 进制。)示例:在二进制中
N 0000 0110 0100 0111
~N - 1111 1001 1011 1000 1 的补码 +1 + 0000 0000 0000 0001 加 1 -N 1111 1001 1011 1001 补码表示
在十六进制中
N 0647
~N - F9B8 1 的补码 +1 + 0001 加 1 -N F9B9 补码表示
计算器将始终直接为您提供补码。最高有效位 (MSB) 是对应于 2 的最大幂的二进制位,对于负补码数字,它始终为 1。因此,它通常被称为符号位。在补码中,-0 = +0。从技术上讲,0 是其自身的补码。
N 00000000
~N - 11111111 1 的补码 +1 + 00000001 加 1 -N 00000000 补码表示
________________________________________ 定长算术问题 溢出和下溢 对于 16 位定长数制,
添加带符号数字很容易超过这些限制。第一位
0011 $3000 0110 $6000 1001 $9000
此结果,来自在数制中添加两个正数,结果为 $9000,它大于 $7FFF,即允许的最大正数。实际上,$9000 等于 1001 0000 0000 0000,它是一个负数。结果的符号与操作数的符号不同。规则:如果在添加两个正补码数字时发生符号变化,则发生了溢出。我们可以将这些规则推广到带符号的加法和减法。
符号扩展 如果数字的长度不同怎么办?十进制 补码 二进制
3-bit 4-bit 8-bit +3 011 0011 00000011 +2 010 0010 00000010 +1 001 0001 00000001 0 000 0000 00000000 -1 111 1111 11111111 -2 110 1110 11111110 -3 101 1101 11111101 -4 100 1100 11111100
要将补码数字扩展到更多的二进制位,您只需将符号位向左继续扩展。示例:将 $9B 扩展到 16 位。$9B = 1001 1011 = 1111 1111 1001 1011 = $FF9B
将 $5F 扩展到 16 位。$5F = 0101 1111 = 0000 0000 0101 1111 = $005F
添加两个不同长度的补码数字 43A0 43A0
9B FF9B need to sign extend; you can't just add zeros.
???? 1 433B
请注意,8 位 $9B 和 16 位 $FF9B 在各自的数制中都表示 -101。