yukki.cn / writing / post-20260920-171729
定点数的编码表示
梳理定点数、真值与机器数的概念,以及原码、反码、补码和移码的表示方法与特点。
计算机只能存储 0 和 1。为了表示正数、负数和小数,需要事先约定符号位、小数点位置以及编码规则。
其中最重要的四种编码是:原码、反码、补码和移码。
真值、机器数与定点数
真值与机器数
真值是数在数学意义上的实际值,例如 +5、−5、+0.75、−0.25。
机器数是该数在计算机中的二进制编码。计算机不能直接存储正负号,因此通常用最高位表示符号:
例如,在 8 位原码中:
(00000101)原=+5,(10000101)原=−5
重点: 真值是数学意义上的数,机器数是按照特定编码规则得到的二进制表示。同一个真值采用不同编码时,机器数可能不同。
以 −5 为例:
| 编码方式 |
8 位机器数 |
| 原码 |
10000101 |
| 反码 |
11111010 |
| 补码 |
11111011 |
| 移码 |
01111011 |
因此,看到机器数 11111011 时,必须先明确它采用的是哪一种编码,才能确定真值。
定点整数与定点小数
定点数的“小数点”位置是事先约定的,机器中通常不实际存储小数点。
- 定点整数: 小数点固定在数值位的最右侧,如 x7x6⋯x0.。
- 定点小数: 小数点固定在符号位之后,如 x0.x1x2⋯x7。
例如,若采用定点小数格式,则:
0.1012=21+81=0.62510
与定点数相对的是浮点数,其小数点位置可以随阶码变化。
下文若无特别说明,统一采用 8 位定点整数:最高位为符号位,其余 7 位为数值位。
原码
原码由“符号位 + 绝对值的二进制表示”组成:正数符号位为 0,负数符号位为 1。
例如:
[+5]原=00000101,[−5]原=10000101
读取原码时,先看符号位,再把其余位按无符号数解释。例如:
(10001101)原=−13,(00001101)原=+13
原码的特点
8 位原码有两个零:
[+0]原=00000000,[−0]原=10000000
由于 1 位用于表示符号,7 位数值位最大只能表示 127,因此其范围为:
−127≤x≤127
原码直观,但不适合直接进行加减运算。例如:
00000101+10000011=10001000
若把结果仍按原码解释,会得到 −8,而实际 5+(−3)=2。这说明原码运算还需要额外处理符号和绝对值。
反码
反码的规则是:
- 正数的反码与原码相同;
- 负数的反码保持符号位为 1,其余数值位全部取反。
例如:
[−5]原=10000101
数值位 0000101 取反后得到 1111010,所以:
[−5]反=11111010
也可以从对应正数的编码出发,将所有位取反:
[+5]反=00000101全部取反[−5]反=11111010
反码仍然有两个零:
[+0]反=00000000,[−0]反=11111111
因此,8 位反码的表示范围仍为:
−127≤x≤127
补码
现代计算机通常使用补码保存和运算有符号整数。
补码的规则是:
- 正数的补码与原码、反码相同;
- 负数的补码等于其反码加 1。
例如:
[−5]原[−5]反[−5]补=10000101=11111010=11111010+1=11111011
负数求补码也可以记为:对应正数的各位全部取反,再加 1。例如:
00001101取反11110010+111110011
所以:
[−13]补=11110011
由补码求真值
若补码最高位为 0,它表示非负数,可以直接读取。若最高位为 1,则对机器数取反加 1,得到其绝对值,再添加负号。
例如:
11111011取反00000100+100000101
因此:
(11111011)补=−5
补码的位权解释
对于 8 位补码 b7b6⋯b0,最高位的权值为 −27,其余位的权值仍为正:
x=−b727+b626+b525+⋯+b020
例如:
(11111011)补=−128+64+32+16+8+2+1=−5
这种方法也能解释特殊编码:
(10000000)补=−128
不能把它按照“符号位 + 后 7 位绝对值”的原码规则读取。
补码的优势
补码可以把减法转换成加法。例如,计算 5+(−3):
[5]补=00000101,[−3]补=11111101
直接相加:
+00000101+11111101100000010
机器字长只有 8 位,丢弃最高位进位后得到 00000010,即 2。
补码还把正零和负零统一为同一个编码:
[0]补=00000000
原本用于表示“负零”的编码位置可用于表示 −128,所以 8 位补码的范围为:
−128≤x≤127
一般地,n 位补码的范围为:
−2n−1≤x≤2n−1−1
移码
移码通常用于表示浮点数的阶码。它通过加入固定偏置,把有符号数映射为无符号编码,从而便于比较大小。
本文采用 8 位移码、偏置量为 27=128:
[x]移=x+128
| 真值 |
加入偏置后的值 |
8 位移码 |
| -128 |
0 |
00000000 |
| -5 |
123 |
01111011 |
| -1 |
127 |
01111111 |
| 0 |
128 |
10000000 |
| +1 |
129 |
10000001 |
| +5 |
133 |
10000101 |
| +127 |
255 |
11111111 |
在这种偏置约定下,同一个数的移码等于其补码的最高位取反,其余位保持不变:
[−5]补=11111011最高位取反[−5]移=01111011
移码按无符号数比较时,编码顺序与真值大小顺序一致:
01111011<10000000<10000101
对应:
−5<0<5
注意: “移码等于补码符号位取反”只适用于偏置为 2n−1 的 n 位移码。IEEE 754 的阶码采用偏置表示,但其偏置值和特殊编码规则需要单独判断。
定点小数的编码
定点小数与定点整数采用相同的编码思想,区别只在于小数点的位置。
假设格式为 x0.x1x2x3x4,其中最高位 x0 是符号位。因为:
0.62510=0.1012
所以:
[+0.625]原=0.1010
对于 −0.625:
[−0.625]原[−0.625]反[−0.625]补=1.1010=1.0101=1.0110
四种编码对比
以 8 位定点整数为例:
| 真值 |
原码 |
反码 |
补码 |
移码 |
| +5 |
00000101 |
00000101 |
00000101 |
10000101 |
| -5 |
10000101 |
11111010 |
11111011 |
01111011 |
| +0 |
00000000 |
00000000 |
00000000 |
10000000 |
| -0 |
10000000 |
11111111 |
无单独编码 |
无单独编码 |
| 编码 |
8 位整数范围 |
主要特点 |
| 原码 |
−127∼127 |
直观,但加减运算不便,有两个零 |
| 反码 |
−127∼127 |
负数数值位取反,仍有两个零 |
| 补码 |
−128∼127 |
加减运算统一,零的编码唯一 |
| 移码 |
−128∼127 |
便于按无符号编码比较大小 |
对于非负数:
原码=反码=补码
在本文的移码约定下,负数的编码转换关系为:
原码数值位取反反码+1补码最高位取反移码
重点: 实际学习和运算中最重要的是补码。要特别记住补码的求法、真值还原、表示范围,以及最高位具有负权这一点。
嘻嘻,美好的周末结束了。
痛苦的上学日又要来了,
如果学校消失,可能更有利于我学习。
今天就不看飞天小女警了,早点睡觉,
留着明天看。😇
