第二章 数据的机器级表示与处理
数制和编码
- 十进制、二进制、十六进制、八进制……
- 定/浮点表示
数制
- 十进制(Decimal):结尾加
D
表示。 - 二进制(Binary):结尾加
B
表示。 - 八进制(Octal):结尾加
O
表示。 - 十六进制(Hexadecimal):结尾加
H
表示或者前缀加0x
表示。
进制转换:
整数部分:除基取余,上左下右
小数部分:乘基取整,上左下右
定点数和浮点数
计算机中只能通过约定小数点的位置来表示小数点
- 小数点位置约定在固定位置的数称为定点数
- 小数点位置约定为可浮动的数称为浮点数
实数的定义:
X
=
(
−
1
)
s
×
M
×
R
E
X=(-1)^s \times M \times R^E
X=(−1)s×M×RE
其中
S
S
S取值为
0
0
0或者
1
1
1,用来决定数
X
X
X的符号;
M
M
M是尾数,
E
E
E是阶/指数。
R
R
R是基数。
定点数的编码
原码、补码、移码、反码
- 原码:最高位的 0 0 0/ 1 1 1表示正负,数值部分不变。但是缺点有: 0 0 0的表示不唯一,不利于编程;加减运算方式不统一;对硬件设计的要求较高;特别是当 a < b a<b a<b时候,实现 a − b a-b a−b比较困难。
- 补码(从50年代以来整数采用的编码方式):
[
X
]
补
=
2
n
+
X
[X]_\text{补}=2^n + X
[X]补=2n+X。同时补码实现了加和减的统一。
结论一:一个负数的补码等于模减该负数的绝对值
结论二:对于某一确定的模,某数减去小于模的另一数,总可以用该数加上另一数负数的补码来代替实现了加法和减法的统一。
变形补码:采用双符号位存放可能溢出的中间结果。
负数的补码的简便求法:从右至左遇到的第一个 1 1 1的前面各位取反(不含这个 1 1 1) - 移码:将每一个数值加上一个偏置常数
bias
。 - 反码:直接将二进制按位取反,一般没什么用。
C语言中的数
整数
其中整数类型分为带符号整数和无符号整数。
整数表示比较简单,大概熟悉C语言的程序员都掌握的比较好。
浮点数
浮点数的表示就很复杂了,编码上有许多细节。
首先是对科学计数法的概念:
- 浮点数的表示范围:
第0位数符S;第1-8位为8位移码表示阶码
E
E
E(偏置常数为128)
第9~31位为24位二进制原码小数表示的尾数
M
M
M。规格化尾数的小数点后第一位总是1,故规定第一位默认的“1”不明显表示出来。这样可用23个 数位表示24位尾数
最大正数:
0.11
…
1
×
2
11
…
11
=
(
1
−
2
−
24
)
×
2
127
0.11 \dots 1 \times 2^{11 \dots 11} = (1-2^{-24}) \times 2 ^{127}
0.11…1×211…11=(1−2−24)×2127
最小正数:
0.10
…
0
×
2
00
…
0
=
(
1
/
2
)
×
2
−
128
0.10 \dots 0 \times 2^{00 \dots 0} = (1/2) \times 2^{-128}
0.10…0×200…0=(1/2)×2−128
- IEEE 754 标准(重点)
- 规格化数
Exponent | Significand | |
---|---|---|
1-254 | 任意小数点前隐含1 | |
0 | 0 | +/-0 |
255 | 0 | +/-inf |
255 | nonzero | NaN |
- 非规格化数
当 E x p o n e n t = = 0 Exponent == 0 Exponent==0 并且 S i g n i f i c a n d ! = 0 Significand != 0 Significand!=0 时,用来表示非规格化数。
非数值表示
西文字符
二进制 | 十进制 | 十六进制 | 缩写 | 可以显示的表示法 | 名称/意义 |
---|---|---|---|---|---|
0000 0000 | 0 | 00 | NUL | ␀ | 空字符(Null) |
0000 0001 | 1 | 01 | SOH | ␁ | 标题开始 |
0000 0010 | 2 | 02 | STX | ␂ | 本文开始 |
0000 0011 | 3 | 03 | ETX | ␃ | 本文结束 |
0000 0100 | 4 | 04 | EOT | ␄ | 传输结束 |
0000 0101 | 5 | 05 | ENQ | ␅ | 请求 |
0000 0110 | 6 | 06 | ACK | ␆ | 确认回应 |
0000 0111 | 7 | 07 | BEL | ␇ | 响铃 |
0000 1000 | 8 | 08 | BS | ␈ | 退格 |
0000 1001 | 9 | 09 | HT | ␉ | 水平定位符号 |
0000 1010 | 10 | 0A | LF | ␊ | 换行键 |
0000 1011 | 11 | 0B | VT | ␋ | 垂直定位符号 |
0000 1100 | 12 | 0C | FF | ␌ | 换页键 |
0000 1101 | 13 | 0D | CR | ␍ | 归位键 |
0000 1110 | 14 | 0E | SO | ␎ | 取消变换(Shift out) |
0000 1111 | 15 | 0F | SI | ␏ | 启用变换(Shift in) |
0001 0000 | 16 | 10 | DLE | ␐ | 跳出数据通讯 |
0001 0001 | 17 | 11 | DC1 | ␑ | 设备控制一(XON 启用软件速度控制) |
0001 0010 | 18 | 12 | DC2 | ␒ | 设备控制二 |
0001 0011 | 19 | 13 | DC3 | ␓ | 设备控制三(XOFF 停用软件速度控制) |
0001 0100 | 20 | 14 | DC4 | ␔ | 设备控制四 |
0001 0101 | 21 | 15 | NAK | ␕ | 确认失败回应 |
0001 0110 | 22 | 16 | SYN | ␖ | 同步用暂停 |
0001 0111 | 23 | 17 | ETB | ␗ | 区块传输结束 |
0001 1000 | 24 | 18 | CAN | ␘ | 取消 |
0001 1001 | 25 | 19 | EM | ␙ | 连接介质中断 |
0001 1010 | 26 | 1A | SUB | ␚ | 替换 |
0001 1011 | 27 | 1B | ESC | ␛ | 跳出 |
0001 1100 | 28 | 1C | FS | ␜ | 文件分割符 |
0001 1101 | 29 | 1D | GS | ␝ | 组群分隔符 |
0001 1110 | 30 | 1E | RS | ␞ | 记录分隔符 |
0001 1111 | 31 | 1F | US | ␟ | 单元分隔符 |
0111 1111 | 127 | 7F | DEL | ␡ | 删除 |
|
|
|
汉字
- 汉字的区位码:由94行、94列组成,行号为区号,列号为位号。
- 汉字的国标码:将区号和位号各自加上32(20H)。国标码中区号和位号各占7位。在计算机内部,为方便处理与存储,前面添一个0,构成一个字节。
- 至少需要2个字节才能表示一个汉字内码(因为汉字总数超过6万个)
数据宽度和储存容量
容量单位
中文 | 表示 | 转化 |
---|---|---|
千字节 | KB | 1 K B = 2 10 字节 = 1024 B 1KB = 2^{10} \text{字节} = 1024 B 1KB=210字节=1024B |
兆字节 | MB | 1 M B = 2 20 字节 = 1024 K B 1MB = 2^{20} \text{字节} = 1024 KB 1MB=220字节=1024KB |
千兆字节 | GB | 1 G B = 2 30 字节 = 1024 M B 1GB = 2^{30} \text{字节} = 1024 MB 1GB=230字节=1024MB |
兆兆字节 | TB | 1 T B = 2 40 字节 = 1024 G B 1TB = 2^{40} \text{字节} =1024 GB 1TB=240字节=1024GB |
通信中的带宽单位
中文 | 表示 | 转化 |
---|---|---|
千比特/秒 | kb/s | 1 k b p s = 1 0 3 b / s = 1000 b p s 1kbps = 10^{3} b/s = 1000 bps 1kbps=103b/s=1000bps |
兆比特/秒 | Mb/s | 1 M b / s = 1 0 6 b / s = 1000 k b p s 1Mb/s = 10^{6} b/s = 1000 kbps 1Mb/s=106b/s=1000kbps |
千兆比特/秒 | Gb/s | 1 G b / s = 1 0 9 b / s = 1000 M b p s 1Gb/s = 10^{9} b/s = 1000 Mbps 1Gb/s=109b/s=1000Mbps |
兆兆比特/秒 | Tb/s | 1 T b / s = 1 0 12 b / s = 1000 G b p s 1Tb/s = 10^{12} b/s =1000 Gbps 1Tb/s=1012b/s=1000Gbps |
注意:容量单位和带宽单位里面明显大小写有一些不一样,因为表示的含义不同,一个是1000,一个1024.
C语言中数据类型的宽度
C声明 | 典型32位机器(单位:字节) | 典型64位机器(单位:字节) |
---|---|---|
char | 1 | 1 |
short int | 2 | 2 |
int | 4 | 4 |
long int | 4 | 8 |
char* | 4 | 8 |
float | 4 | 4 |
double | 8 | 8 |
long double 的确切精度没有规定,所以对于不同平台来说,有的是8字节,有的是10字节,有的是12字节或者16字节。
数据的存储和排列顺序
80年代开始,几乎所有通用计算机都采用字节编址。在高级语言中声明的基本数据类型有char、short、int、long、long long、float、double、long double等各种不同长度数据,一个基本数据可能会占用多个存储单元。所以有一些问题我们还需要考虑,比如说:变量的地址是其最大地址还是最小地址?多个字节在存储单元中存放的顺序如何?
大/小端方式
测试代码:
#include < cstdio >
#include < cstring >
#include < algorithm >
using namespace std;
const int maxn=200005;
int main()
{
union NUM
{
int a;
char b;
} num;
num.a=0x12345678;
if(num.b==0x12) printf("Big Endian\n");
else printf("Little Endian\n");
printf("num.b=0x%X\n",num.b);
return 0;
}
在我的机器上运行的结果:
大小端非常重要,因为在看指令的时候,大小端不同,表示的值就不同。
注意:IA-32采用的是小端方式。
数字逻辑电路
布尔代数
A A A | B B B | A ⋅ B A \cdot B A⋅B | A + B A+B A+B | A ˉ \bar{A} Aˉ | A ⊕ B A \oplus B A⊕B |
---|---|---|---|---|---|
0 | 0 | 0 | 0 | 1 | 0 |
0 | 1 | 0 | 1 | 1 | 1 |
1 | 0 | 0 | 1 | 0 | 1 |
1 | 1 | 1 | 1 | 0 | 0 |
全加器(一位加法器)
两个加数为
A
A
A和
B
B
B,低位进位为Cin
,和为
F
F
F,向高位的进位为Cout
。
化简之后,逻辑表达式如下:
F
=
A
⊕
B
⊕
C
i
n
F=A \oplus B \oplus Cin
F=A⊕B⊕Cin
C
o
u
t
=
A
⋅
B
+
A
⋅
C
i
n
+
B
⋅
C
i
n
Cout=A \cdot B + A \cdot Cin + B \cdot Cin
Cout=A⋅B+A⋅Cin+B⋅Cin
n位加法器
n位加法器可用n个全加器实现
无符号整数加
带符号整数加
- 溢出标志OF: O F = C n ⊕ C n − 1 OF=C_n \oplus C_{n-1} OF=Cn⊕Cn−1
- 符号标志SF: S F = F n − 1 SF=F_{n-1} SF=Fn−1
- 零标志ZF: Z F = 1 ZF=1 ZF=1当且仅当 F = 0 F=0 F=0
- 进位/借位标志CF: C F = C o u t ⊕ C i n CF=Cout \oplus Cin CF=Cout⊕Cin
n位整数加/减运算器
[
A
+
B
]
补
=
[
A
]
补
+
[
B
]
补
(
m
o
d
2
n
)
[A+B]_{\text{补}} = [A]_{\text{补}} + [B]_{\text{补}} (mod\;\;2^n)
[A+B]补=[A]补+[B]补(mod2n)
[
A
−
B
]
补
=
[
A
]
补
+
[
−
B
]
补
(
m
o
d
2
n
)
[A-B]_{\text{补}} = [A]_{\text{补}} + [-B]_{\text{补}} (mod\;\;2^n)
[A−B]补=[A]补+[−B]补(mod2n)
- 当 S u b Sub Sub为 1 1 1时,做减法。
- 当 S u b Sub Sub为 0 0 0时,做加法。
算术逻辑部件ALU
:
数据的运算
高级语言程序中涉及的运算(以C语言为例)
- 整数算术运算、浮点数算术运算
- 按位、逻辑、移位、位扩展和位截断等运算
指令集中涉及到的运算:
涉及到的定点数运算
:
算术运算:
- 带符号整数:取负/ 符号扩展/ 加/ 减/ 乘/ 除 / 算术移位
- 无符号整数:0扩展/ 加/ 减/ 乘/ 除/ 逻辑左移/ 逻辑右移
逻辑运算:
- 逻辑操作:与/ 或/ 非/ …
涉及到的浮点数运算
:加、减、乘、除
指令中的运算操作在运算电路中进行
- 基本运算部件ALU、通用寄存器组,以及其他部件
整数的加减运算
- 计算机中所有运算都基于加法器实现。
- 加法器不知道所运算的是带符号数还是无符号数。
- 加法器不判定对错,总是取低n位作为结果,并生成标志信息。
无符号数
加法:
- 当 x + y < 2 n , r e s u l t = x + y x+y < 2^n, result=x+y x+y<2n,result=x+y
- 当 2 n ≤ x + y < 2 n + 1 , r e s u l t = x + y − 2 n 2^n \leq x+y < 2^{n+1}, result=x+y-2^n 2n≤x+y<2n+1,result=x+y−2n
减法:
- 当 x − y < 0 , r e s u l t = x − y + 2 n x-y<0, result=x-y+2^n x−y<0,result=x−y+2n
- 当 x − y ≥ 0 , r e s u l t = x − y x-y \geq 0, result=x-y x−y≥0,result=x−y
带符号数
加法:
- 当 x + y < − 2 n − 1 , r e s u l t = x + y + 2 n x+y<-2^{n-1}, result=x+y+2^n x+y<−2n−1,result=x+y+2n,负溢出
- 当 − 2 n − 1 ≤ x + y < 2 n − 1 , r e s u l t = x + y -2^{n-1} \leq x+y < 2^{n-1}, result=x+y −2n−1≤x+y<2n−1,result=x+y,正常
- 当 x + y ≥ 2 n − 1 , r e s u l t = x + y − 2 n x+y \geq 2^{n-1}, result=x+y-2^n x+y≥2n−1,result=x+y−2n,正溢出
减法:
- 当 x − y < − 2 n − 1 , r e s u l t = x − y + 2 n x-y<-2^{n-1}, result=x-y+2^n x−y<−2n−1,result=x−y+2n,负溢出
- 当 − 2 n − 1 ≤ x − y < 2 n − 1 , r e s u l t = x − y -2^{n-1} \leq x-y <2^{n-1}, result=x-y −2n−1≤x−y<2n−1,result=x−y,正常
- 当 x − y ≥ 2 n − 1 , r e s u l t = x − y − 2 n x-y \geq 2^{n-1}, result=x-y-2^n x−y≥2n−1,result=x−y−2n,正溢出