计算机中数制系统及数值表示全解析
1. 引言
在计算机领域,数制系统和数值表示是基础且关键的知识。不同的数制系统在计算机的各个方面都有着广泛应用,了解它们之间的转换以及数值的内部表示方式,对于理解计算机的工作原理至关重要。本文将详细介绍几种常见的数制系统,包括十进制、二进制、八进制和十六进制,以及整数和浮点数的表示方法。
2. 位置计数系统
位置计数系统是一种用数字序列表示数值的方法,每个数字的位置决定了它的权重。常见的十进制就是典型的位置计数系统,与之不同,罗马数字系统并非位置计数系统。
每个位置计数系统都有一个基数(或称为底数)和一个字符集。基数是一个正整数,字符集中符号的数量等于数制的基数。例如,十进制系统的基数是 10,其字符集包含 0 到 9 共 10 个数字。
在计算机系统和编程中,常用的位置计数系统有十进制(基数为 10)、二进制(基数为 2)、八进制(基数为 8)和十六进制(基数为 16)。引入熟悉的十进制系统是为了解释位置计数系统的一些基本概念。计算机内部使用二进制系统,而八进制和十六进制主要是为了方便表示二进制数。
在位置计数系统中,数字序列中的每个数字都应是字符集中的符号,且每个位置都有权重。如果从右向左从 0 开始计数位置,基数为 b 的数制中第 n 位的权重是 (b^n)。例如,十进制数 579 可表示为 (5\times(10^2)+ 7\times(10^1)+ 9\times(10^0))。
更一般地,基数为 b 的数制中的一个数可表示为 (d_n d_{n - 1} … d_1 d_0),其中 (d_0) 表示最低有效位(LSD),(d_n) 表示最高有效位(MSD),该序列表示的值为 (d_n b^n + d_{n - 1} b^{n - 1} + … + d_1 b^1 + d_0 b^0)。
每个数字 (d_i) 的取值范围是 (0 \leq d_i \lt (b - 1))。当 (b \lt 10) 时,使用前 b 个十进制数字;当 (b \gt 10) 时,使用英文字母的开头部分来表示大于 9 的数字。例如,十六进制系统的基数是 16,其字符集为 0 到 9 和 A 到 F,共 16 个符号。在数制中,大小写字母被视为等价。
在基数为 b 的系统中,使用 n 位数字可以表示 (b^n) 个不同的值,最大的数是 ((b^n - 1)),可写为 ((b - 1)(b - 1) … (b - 1)(b - 1))(共 n 位)。表示 X 个不同值所需的最少位数(即数字的长度)为 ([log_b X]),其中 ([ ]) 表示向上取整函数。
3. 数制表示符号
由于多个数制系统的字符集存在共性,容易产生混淆。例如,若不指定数制而直接写 100,可能有不同的解释,对应不同的十进制值,如下表所示:
| 数制 | 数值 | 十进制值 |
| — | — | — |
| 二进制 | 100 | 4 |
| 十进制 | 100 | 100 |
| 八进制 | 100 | 64 |
| 十六进制 | 100 | 256 |
因此,明确指定数制(即指定基数)很重要。一种常见的表示方法是在数字后面附加一个字母(大写或小写)来指定数制。例如,D 表示十进制,B 表示二进制,Q 表示八进制,H 表示十六进制。有些汇编器使用前缀 Ox 表示十六进制,前缀 0 表示八进制。
4. 常见数制系统介绍
- 十进制系统 :在日常生活中广泛使用,基数为 10,字符集包含 0 到 9 共 10 个数字,推测是因为人类有 10 根手指和脚趾用于计数。
- 二进制系统 :计算机内部使用的数制系统,基数为 2,字符集只有 0 和 1。每个二进制数字称为一个位(bit),例如 1021 不是有效的二进制数。使用 n 位二进制数可以表示从 0 到 ((2^n - 1)) 共 (2^n) 个不同的值。
- 八进制系统 :基数为 8,字符集包含 0 到 7 共 8 个数字,例如 181 不是有效的八进制数。八进制数常用于紧凑地表示二进制数,使用 8 位二进制数表示 256 个不同的值,而在八进制系统中只需 3 位。例如,八进制数 230Q 对应的二进制数是 10011000B,二进制数较长且易读性差。一般来说,八进制可以将二进制数的长度缩短为原来的三分之一,并且转换回二进制数也很简单。
- 十六进制系统 :基数为 16,字符集包含 0 到 9 和 A 到 F 共 16 个符号。在本文中,统一使用大写字母,但大小写字母可互换。例如,FEED 是有效的十六进制数,而 GEFF 不是。十六进制主要用于方便地表示长二进制数,可将二进制数的长度缩短为原来的四分之一。例如,二进制数 10011000B 可表示为 98H。调试器通常以十六进制形式显示地址、数据等信息。
5. 数制转换
-
转换为十进制
:将基数为 b 的数制中的数转换为十进制,只需按照公式 (d_n b^n + d_{n - 1} b^{n - 1} + … + d_1 b^1 + d_0 b^0) 进行算术计算,即每个数字乘以其权重并相加。例如,将二进制数 10100111B 转换为十进制数:
[
\begin{align }
10100111_B&= 1\times 2^7 + 0\times 2^6 + 1\times 2^5 + 0\times 2^4 + 0\times 2^3 + 1\times 2^2 + 1\times 2^1 + 1\times 2^0\
&= 128 + 0 + 32 + 0 + 0 + 4 + 2 + 1\
&= 167_D
\end{align }
] -
从十进制转换
:将十进制数转换为目标数制的方法如下:
- 将十进制数除以目标数制的基数,记录商和余数。
- 重复步骤 1,不断用商除以基数,记录每次的余数,直到商为 0。
- 将过程中产生的余数从左到右按相反顺序排列,得到目标数制中的等效数字。
例如,将十进制数 167 转换为二进制数:
| 除法运算 | 商 | 余数 |
| — | — | — |
| 167 / 2 | 83 | 1 |
| 83 / 2 | 41 | 1 |
| 41 / 2 | 20 | 1 |
| 20 / 2 | 10 | 0 |
| 10 / 2 | 5 | 0 |
| 5 / 2 | 2 | 1 |
| 2 / 2 | 1 | 0 |
| 1 / 2 | 0 | 1 |
将余数从左到右按相反顺序排列,得到二进制数 10100111B,与前面的转换结果一致。
-
二进制/八进制/十六进制转换
-
二进制/八进制转换 :将二进制数转换为八进制数,从右开始每 3 位一组,若位数不是 3 的倍数,在左边补 0。然后将每组 3 位二进制数替换为对应的八进制数字。这是因为 (2^3 = 8)。例如:
[
\begin{align }
1000101_B&= ‘001’ ‘000’ ‘101’_B\
&= 105_Q
\end{align }
]
[
\begin{align }
10100111_B&= ‘010’ ‘100’ ‘111’_B\
&= 247_Q
\end{align }
]
将八进制数转换为二进制数,只需将每个八进制数字替换为对应的 3 位二进制数。例如:
[
\begin{align }
105_Q&= 001 000 101_B\
247_Q&= ‘010’ ‘100’ ‘111’_B
\end{align }
]
如果需要 8 位二进制数,可去掉前面的 0。 -
二进制/十六进制转换 :将二进制数转换为十六进制数,从右开始每 4 位一组,若位数不是 4 的倍数,在左边补 0。然后将每组 4 位二进制数替换为对应的十六进制数字,因为 (2^4 = 16)。例如:
[
\begin{align }
1101011111_B&= ‘0011’ ‘0101’ ‘1111’_B\
&= 35F_H
\end{align }
]
将十六进制数转换为二进制数,将每个十六进制数字替换为对应的 4 位二进制数。例如:
[
\begin{align }
B01D_H&= ‘1011’ ‘0000’ ‘0001’ ‘1101’_B
\end{align }
]
-
6. 整数的表示
- 无符号整数 :表示无符号(即非负)整数最自然的方法是使用等效的二进制表示。如前所述,n 位二进制数可以表示 (2^n) 个不同的值,范围从 0 到 ((2^n - 1))。可以在左边补 0 使十进制数的二进制转换结果恰好为 N 位,这个过程称为零扩展,适用于无符号数。但如果一个整数的二进制表示所需的位数超过了 N 位,那么这个数就超出了使用 N 位所能表示的范围。
-
有符号整数
:有符号数有多种表示方法,包括原码、移码、反码和补码。
- 原码表示 :在原码表示中,用一位来表示数的符号,通常最高有效位作为符号位,0 表示正数,1 表示负数。如果用 N 位表示一个数,那么有 ((N - 1)) 位可用于表示数的绝对值。例如,当 N 为 4 时,4 位原码表示的数的范围是 (-2^{n - 1} + 1) 到 (+2^{n - 1} - 1),且 0 有两种表示:+0 和 -0。
- 移码表示 :在这种方法中,将一个数映射到一个非负整数,以便使用其二进制表示。通过给要表示的数加上一个称为偏移量(bias)的值来实现这种转换。对于 n 位表示,偏移量应使得映射后的数小于 (2^n)。要找到一个数在这种方法中的二进制表示,只需将偏移量 M 加到该数上,然后找到对应的二进制表示。例如,在偏移量为 7 的系统中,-3D 表示为 (-3 + 7 = +4 = 0100B)。用移码表示的数称为带偏整数,这种表示方法常用于浮点数表示中存储指数值。
-
反码表示
:与移码表示类似,在反码和补码表示中,负数都有偏移。对于正数,使用标准的二进制表示。与原码表示一样,最高有效位表示符号(0 为正,1 为负)。在反码表示中,负数的偏移量为 (b^n - 1),对于二进制情况,偏移量为 (2^n - 1)。对于负数 (-X),其表示为 ((2^n - 1) - X) 的二进制表示。例如,当 n 为 4 时,(-5) 可表示为:
[
\begin{align*}
2^4 - 1&= 1111_B\
-
5&= -0101_B\
1010_B
\end{align*}
]
可以看到,一个数的反码可以通过对其各个位取反得到。在这种方法中,0 也有两种表示。表示有符号数的反码允许使用比原码和移码更简单的电路来进行加法和减法运算,但 0 的两种表示是一个问题,并且符号位产生的进位必须加到结果中。-
补码表示
:在补码表示中,正数的表示与原码和反码相同。负数的偏移量为 (2^n),因此负数 (-X) 用 n 位表示为 ((2^n - X))。由于偏移量比反码表示中的大 1,所以在取反后需要加 1 才能得到负数的补码表示,并且可以丢弃符号位产生的任何进位。例如,(-5) 可表示为:
[
\begin{align }
5_D&= 0101_B \xrightarrow{取反} 1010_B\
& \xrightarrow{加 1} 1011_B
\end{align }
]
因此,1011B 在补码表示中表示 (-5D)。n 位补码整数的范围是 (-2^{n - 1}) 到 (+2^{n - 1} - 1)。例如,使用 8 位时,范围是 -128 到 +127。要找到补码表示中负数的绝对值,只需对该数取反加 1 并丢弃最左边位产生的任何进位。
-
补码表示
:在补码表示中,正数的表示与原码和反码相同。负数的偏移量为 (2^n),因此负数 (-X) 用 n 位表示为 ((2^n - X))。由于偏移量比反码表示中的大 1,所以在取反后需要加 1 才能得到负数的补码表示,并且可以丢弃符号位产生的任何进位。例如,(-5) 可表示为:
7. 符号扩展
对于有符号数的扩展,不能像无符号整数那样在左边补 0,因为最高有效位表示符号。要扩展有符号数,需要复制符号位。例如,(-5) 在补码表示中为 1011B,若要将其扩展为 8 位,则表示为 11111011B;扩展为 16 位则为 1111111111111011B。这个过程称为符号扩展。
8. 浮点数表示
使用十进制系统时,可以用科学记数法表示非常小和非常大的数,如 (1.2345\times 10^{22}) 和 (9.876543\times 10^{-33})。用位置计数法表示这些数既困难又容易出错,且需要更多空间。同样,二进制数也可以用科学记数法表示,例如 (+1101.101\times 2^{+11100} = 13.625\times 2^{28} = 4.57179\times 10^{9})。
用这种记数法表示的数有两部分:尾数(或有效数字)和指数,每部分都可以有一个符号(+ 或 -)。用这种记数法表示的数可以有多种等效形式,这会给算术运算、比较等带来实现问题。通过引入一种称为标准形式(即规范化形式)可以避免这个问题。在二进制情况下,规范化的二进制形式具有以下格式:
(\pm1.X_1 X_2 … X_{M - 1} X_M \times 2^{\pm Y_{N - 1} Y_{N - 2} … Y_1 Y_0})
其中 (X_i) 和 (Y_j) 表示一个位,(1\leq i\leq M),(0\leq j\leq N)。例如,(+1101.101\times 2^{+11100}) 的规范化形式是 (+1.101101\times 2^{+11101}),通常写成 (+1.101101E11101)。
为了表示这样的规范化数,可以使用以下格式:
[
\begin{align
}
& \text{单精度:}\
& \begin{array}{|c|c|c|}
\hline
\text{符号(1 位)} & \text{指数(8 位)} & \text{尾数(23 位)}\
\hline
\end{array}\
& \text{双精度:}\
& \begin{array}{|c|c|c|}
\hline
\text{符号(1 位)} & \text{指数(11 位)} & \text{尾数(52 位)}\
\hline
\end{array}
\end{align
}
]
其中 (S_m) 和 (S_e) 分别表示尾数和指数的符号。
浮点数的实现通常会因效率原因或遵循标准而与这种通用格式有所不同。接下来讨论 IEEE 754 浮点数标准的格式,这种标准对于在不同计算机系统之间交换数据和编写高效的数值软件库很有用。
单精度和双精度浮点数格式有以下特点:
1. 尾数只存储规范化数的小数部分,二进制点左边的 1 不明确存储,而是隐含的,以节省一位。但表示 0.0 需要特殊处理。
2. 指数没有符号位,而是转换为移码形式存储。对于单精度数,使用的偏移量是 127D(= 7FH);对于双精度数,是 1023(= 3FFH)。
9. 特殊值的表示
0 和无穷大((\infty))的表示需要特殊处理,如下表所示:
| 特殊数字 | 符号 | 指数(带偏) | 尾数 |
| — | — | — | — |
| +0 | 0 | 0 | 0 |
| -0 | 1 | 0 | 0 |
| +(\infty) | 0 | FFH | 0 |
| -(\infty) | 1 | FFH | 0 |
| NaN | 0/1 | FFH | (\neq0) |
| 非规范化数 | 0/1 | 0 | (\neq0) |
零由零指数和零尾数表示,根据符号位可以有 +0 或 -0。全为 1 的指数表示一个特殊的浮点数。全为 1 的指数和零尾数表示无穷大,符号位表示无穷大的符号。全为 1 的指数和非零尾数表示非数(NaN),NaN 值用于表示像 0/0 和 (\sqrt{-1}) 这样的运算结果。
非规范化数用于表示小于规范化浮点数所能表示的最小值的值。对于非规范化数,二进制点左边的隐含 1 变为 0。最小的规范化数的指数为 1(注意不允许为 0),尾数为 0,因此最小的数是 (1\times 2^{-126})。最大的非规范化数的指数为 0,尾数全为 1,大约表示 (0.9999999\times 2^{-126})。最小的非规范化数的指数为 0,尾数的最后一位为 1,即表示 (2^{-23}\times 2^{-126}),大约为 (10^{-45})。
10. 总结
本文详细介绍了计算机中数制系统和数值表示的相关知识。位置计数系统以基数和字符集为特征,常见的有十进制、二进制、八进制和十六进制。计算机内部使用二进制系统,八进制和十六进制主要用于方便表示二进制数。
在使用多个数制系统时,经常需要进行数制转换,二进制、八进制和十六进制之间的转换相对简单直接,同时也介绍了十进制与二进制之间的转换方法。
整数的表示分为无符号整数和有符号整数,无符号整数使用二进制表示,有符号整数有原码、移码、反码和补码四种表示方法,现代计算机系统通常使用补码表示。
浮点数表示大多遵循 IEEE 754 标准,浮点数由尾数、指数和尾数的符号三部分组成,指数以带偏整数的形式存储。了解这些数制系统和数值表示方法对于深入理解计算机的工作原理和编程至关重要。
计算机中数制系统及数值表示全解析
11. 数制系统的实际应用场景
在计算机领域的不同场景下,各种数制系统发挥着独特的作用,下面详细介绍它们在不同方面的应用。
-
十进制系统
-
日常生活计算
:在日常生活的各种计算中,如购物消费、统计数据等,十进制是最常用的数制。因为人类的计数习惯和手指数量的关系,十进制易于理解和使用。
-
财务系统
:在金融领域,货币的计算和记录都使用十进制。例如,银行账户的余额、交易金额等都是以十进制表示,确保数据的准确性和易于处理。
-
二进制系统
-
计算机硬件底层
:计算机的硬件电路基于二进制逻辑,所有的数据和指令最终都以二进制形式存储和处理。例如,计算机的内存、硬盘等存储设备,以及 CPU 的运算单元,都是基于二进制进行工作的。
-
网络通信
:在网络通信中,数据以二进制的比特流形式传输。例如,以太网协议中,数据帧的传输就是通过二进制信号在物理线路上进行的。
-
八进制系统
-
Unix/Linux 系统权限设置
:在 Unix/Linux 系统中,文件和目录的权限设置使用八进制数表示。例如,权限 755 表示文件所有者具有读、写、执行权限(7 = 4 + 2+ 1),而组用户和其他用户具有读和执行权限(5 = 4+ 1)。
-
早期计算机系统
:在早期的计算机系统中,八进制常用于表示二进制数据。因为八进制与二进制的转换相对简单,方便程序员进行代码编写和调试。
-
十六进制系统
-
编程中的内存地址表示
:在编程中,十六进制常用于表示内存地址。例如,在 C 或 C++ 编程中,调试器显示的内存地址通常是以十六进制形式呈现的,方便程序员定位和分析内存中的数据。
-
图形设计和网页开发
:在图形设计和网页开发中,颜色通常用十六进制代码表示。例如,#FF0000 表示红色,这种表示方法简洁明了,易于在代码中使用。
12. 数制转换的优化方法
在实际应用中,数制转换可能会频繁发生,因此优化转换方法可以提高程序的性能。以下是一些常见的优化思路和示例代码(使用 Python 语言)。
-
使用位运算进行二进制和十六进制转换
- 位运算可以直接操作二进制位,避免了繁琐的算术运算。例如,将二进制数转换为十六进制数:
binary_num = '1101011111'
# 将二进制字符串转换为整数
int_num = int(binary_num, 2)
# 将整数转换为十六进制字符串
hex_num = hex(int_num)[2:]
print(hex_num) # 输出: 35f
- 同样,将十六进制数转换为二进制数:
hex_num = '35f'
# 将十六进制字符串转换为整数
int_num = int(hex_num, 16)
# 将整数转换为二进制字符串,去掉前缀 '0b',并补齐到 12 位
binary_num = bin(int_num)[2:].zfill(12)
print(binary_num) # 输出: 001101011111
-
预先计算转换表
- 对于一些常用的数制转换,可以预先计算并存储转换表,避免重复计算。例如,将 0 - 15 的十进制数转换为对应的十六进制字符的表:
hex_table = '0123456789ABCDEF'
decimal_num = 13
hex_char = hex_table[decimal_num]
print(hex_char) # 输出: D
13. 整数表示在编程中的应用
在编程中,正确理解和使用整数的表示方法对于编写高效、安全的代码至关重要。
-
无符号整数的应用
-
数组索引
:在编程中,数组的索引通常使用无符号整数。因为数组的索引不能为负数,使用无符号整数可以确保索引的有效性。例如,在 C 语言中:
#include <stdio.h>
int main() {
int arr[5] = {1, 2, 3, 4, 5};
unsigned int index = 2;
printf("%d\n", arr[index]); // 输出: 3
return 0;
}
- **内存地址计算**:内存地址通常使用无符号整数表示,因为内存地址是一个非负的数值。例如,在指针操作中,指针的值就是一个无符号整数,表示内存中的一个地址。
-
有符号整数的应用
- 数学计算 :在进行数学计算时,有符号整数可以表示正数和负数,满足各种计算需求。例如,在计算两个数的差值时,结果可能是正数或负数。
a = 5
b = 8
result = a - b
print(result) # 输出: -3
- **表示温度、海拔等物理量**:在表示具有正负意义的物理量时,如温度、海拔等,有符号整数是合适的选择。
14. 浮点数表示的精度问题
浮点数在计算机中的表示存在精度问题,这是由于其二进制表示的特性导致的。下面通过示例和分析来了解这个问题。
-
精度丢失的示例
a = 0.1
b = 0.2
c = a + b
print(c) # 输出: 0.30000000000000004
在这个示例中,0.1 和 0.2 在二进制中是无限循环小数,计算机只能近似表示,因此相加的结果会出现精度丢失。
-
解决精度问题的方法
-
使用 Decimal 模块(Python)
:Python 的 Decimal 模块提供了更高精度的十进制浮点数运算。
from decimal import Decimal
a = Decimal('0.1')
b = Decimal('0.2')
c = a + b
print(c) # 输出: 0.3
- **控制小数位数**:在实际应用中,可以根据需要控制浮点数的小数位数,避免不必要的精度误差。例如,使用 round() 函数进行四舍五入:
a = 0.1
b = 0.2
c = a + b
rounded_c = round(c, 1)
print(rounded_c) # 输出: 0.3
15. 数制系统和数值表示的未来发展趋势
随着计算机技术的不断发展,数制系统和数值表示也可能会有新的发展和变化。
-
量子计算中的数制
:量子计算使用量子比特(qubit)进行计算,其状态可以是 0、1 或两者的叠加态。这可能会引入新的数制和数值表示方法,以充分发挥量子计算的优势。
-
人工智能和大数据中的数值表示
:在人工智能和大数据领域,对数值表示的精度和效率提出了更高的要求。可能会出现新的数值表示方法,以更好地处理大规模数据和复杂的计算任务。
16. 总结与展望
本文全面介绍了计算机中数制系统和数值表示的相关知识,包括位置计数系统的原理、常见数制系统的特点、数制转换的方法、整数和浮点数的表示等内容。同时,还探讨了数制系统在实际应用中的场景、数制转换的优化方法、整数表示在编程中的应用以及浮点数表示的精度问题。
数制系统和数值表示是计算机科学的基础,深入理解这些知识对于学习计算机编程、算法设计、计算机体系结构等领域至关重要。随着计算机技术的不断发展,我们需要不断关注和研究新的数制系统和数值表示方法,以适应未来技术的需求。希望本文能够帮助读者更好地理解和应用这些知识,在计算机领域取得更好的发展。
下面是一个简单的 mermaid 流程图,展示了十进制转换为二进制的过程:
graph TD;
A[开始] --> B[输入十进制数];
B --> C{商是否为 0};
C -- 否 --> D[除以 2,记录商和余数];
D --> C;
C -- 是 --> E[将余数按相反顺序排列];
E --> F[输出二进制数];
F --> G[结束];
通过这个流程图,可以更直观地理解十进制转换为二进制的步骤。在实际应用中,我们可以根据这个流程编写相应的代码来实现转换功能。
超级会员免费看
959

被折叠的 条评论
为什么被折叠?



