Skip to content
On this page

数据的位表示

本文由22秋刘助教提供

整数:补码 (2's complement)

编码

编码是给定位数的二进制串到数字的映射,可以看成一个函数

例如, 位的原码是一种编码:

2 位的补码也是一种编码:

编码 的值域是该编码能表示的数的集合。例如, 位原码的值域是

负数

原码只能表示正数。那么,一个兼容负数的编码 该如何设计呢?

从计算机硬件的角度考量,无符号数(原码)的加法器和乘法器是必须的(我们的 LC-3 虽然没有乘法指令,但你也可以自己补充)

我们希望 编码下,数字的加法,乘法也能兼容无符号数的加法,乘法

  • 减法即加上相反数,因此 编码只需要考虑加法,不需要额外考虑减法

给出 应该满足的性质:

  1. 该编码下数字的加法应该等于编码之和(复用无符号数的加法器)
  1. 该编码下数字的乘法也应该等于编码的乘法(复用无符号数的乘法器)
  1. 该编码应该能表示尽可能多的数字,我们假设 是一一映射(即存在反函数 )

  2. 该编码值域应该是连续的 ,其中 ,结合性质三可知

解法一:

性质二代入 ,得

等式左侧 是一个变量,等式右侧 是一个常数,得

性质二代入 ,得

同理,得

再解 :

在性质一中令 ,并取

同时取反函数

已知 ,自然有

同理

归纳,便得到所有负数 对应的补码

而

归纳,便得到所有正数 的补码

到这里,任意给定一个 位二进制串,我们已经能够确定它实际表示的数字了

对于一个二进制串 :

  • 若
  • 若

所表示的数是正数还是负数由给定的值域确定:二者只有一个是在给定的值域内的(因为值域的长度恰好是二者之差 )

事实上, 只要满足 ,它们具体的值是可以任意选取的:

注意到一个二进制串作为正数和作为负数的取值恰好相差 ,而性质一和二都是模 而言的,可以验证对于不同的 ,这两条性质都成立

这也就导致符合要求的编码方式 不唯一

方便起见,一般约定 开头的二进制串用来表示负数,即编码值域 ,这也就是通常意义上的补码

解法二:

如果考虑溢出,无符号数的加法(乘法)器的一个更合适的称呼是模 的同余等价类的加法(乘法)器

例如,在 4 位原码下, ,对于无符号数而言,这会被认为是溢出

但如果按照模 的同余等价类的观点来看,

最后的等号是顺理成章的,因为 和 不过是同一个等价类的两个代表元

在这个意义上,性质一和性质二的同余符号就不再需要了

从代数结构的角度,这说明二进制串的结构是一个环,且与模 的同余等价类同态

不太严谨地,我们直接得出结论

具体 的取值由值域给定

负数的补码表示:

在明白了补码的结构之后,可以轻松证明 的补码表示就是 的补码表示取反再加一

首先有

两边取反函数

移项

浮点数:IEEE 754

以 32 位单精度浮点数为例

float32 内存表示

浮点数类似于科学计数法,分别储存一个数的有效数字和指数

sign 符号位

用于标识正负,0 代表正,1 代表负

exponent 指数位

8 位无符号整数,范围 ,实际表示的指数需要减去偏移量

及 是特殊取值,具体含义后文介绍

fraction 尾数位

二进制数的第一位有效数字必定是 ,在这之后的 23 位有效数字保存在尾数位 中

故实际有效数字为:

float32 含义及转换

一般来说 (),一个 float32 表示的值为:

求出 三部分的过程就是一个数转换为浮点数的过程

  • 先将一个数转换为二进制
  • 再正则化处理(分解成有效数字和指数)
  • 最后按 IEEE 规约,填入符号位,指数位,尾数位

非正规形式

即 时,此时是浮点数的非正规形式,用来表示极接近 的数字,可以认为此时有效数字只有尾数的 位,不再假定有第一个有效数字

尾数位代表的有效数字是

约定此时指数位的值与 时相同,为 (这么约定是为了让浮点数的一般形式和非正规形式的值域连续)

实际表示的值

最小的非 正浮点数是

有趣的是,浮点数的 其实有两个,在指数位和尾数位全为 时,根据符号位不同,有 和

计算 ,结果正无穷(这是 IEEE 754 标准指定的,但不同编程语言考虑体系结构等因素会有不同的实现,故这个运算仅做了解,此处仅展示两个 符号位不同导致的区别)

JavaScript 试一试

计算 ,结果负无穷

JavaScript 试一试

虽然这两个零符号不同,但根据标准,它们在比较时应该是相等的(因此在写代码时,可以不太考虑这两个 的区别)

JavaScript 试一试

特殊值

当 时:

  • 若小数部分为 0,表示(正/负)无穷(正如上面试一试中你能够得到的结果)
  • 若小数部分不为 0,表示 NaN (Not a Number)

NaN 仅在含义上表示(这个运算结果)不是一个数,但在类型上,NaN 毫无疑问是一个(特殊的)(浮点)数

JavaScript 试一试

结果应该为 number