看原文https://dyingdown.github.io/2020/03/05/Data-Representation/
最近开课计算机组成原理,由于疫情原因,老师推荐的华中科技大学的秦磊华老师讲的MOOC上的课程。感觉学习难度比较大,因为基础薄弱,所以来总结一下学习的知识,加以巩固。
机器数及其特点
首先要了解计算机内部的数据到底是怎么表示的。学习过模电我们都应该知道,计算机内的数据是以二进制形式存储的,因为二进制只包含两个状态,更好表示。如果我们能在二进制的基础上更好的组织数据,则计算机的运算就能更加高效。
数据表示有以下考虑因素:
- 计算机支持的数据类型
- 计算机能表示的数据范围
- 计算机能表示的数据精度
- 存储和处理的代价
- 是否有利于软件的移植等…
在这些基础上我们来对数据进行处理。
真值
首先,在实际运算中,拿到一个数,我们把它转换成二进制数时,+
-
就是符号位。变成二进制数还是用+
-
来表示。这样的带符号的二进制。
比如 − 5 -5 −5 真值就是 − 101 -101 −101; + 5 +5 +5 的真值就是 + 101 +101 +101
这种表示方法很直观,人眼一下就能知道是正数负数。但是计算机怎么办呢?让它去识别加号吗?只有0 1 两种状态,怎么搞个加号进去?所有就有了符号数值化。有了一个新的表示方法:
原码
我看老师的课件上给的定义是这样的
[ X ] 原 = { X 0 ≤ X ≤ 2 n 2 n − X 2 − n ≤ X ≤ 0 [X]_{\mathbb{原}}=\left\{\begin{array}{l} X \space \space \space \space\space \space\space \space\space \space\space \space0 \leq X \leq 2^n\\ 2^{n}-X \space \space \space 2^{-n} \leq X \leq 0 \end{array}\right. [X]原={ X 0≤X≤2n2n−X 2−n≤X≤0
原码就是在真值的基础上,把符号位用0 1表示。一般规定0表示正数,1表示负数。这有点违背我们的常理,我搜了好久也没找到这样规定是出于什么原因,但好像计算机里面表示数N是 ( − 1 ) S N (-1)^SN (−1)SN,S = 0 时就是1, 为正数。反之亦然。S就是那个符号位对应的0或1。
所以举个例子来说: − 5 -5 −5 的原码就是 1101 1101 1101; + 5 +5 +5 的原码就是 0101 0101 0101
OK,问题解决了,就用原码表示吧。接下来开始运算。
先算个 5 + 5 5+5 5+5 吧。假设字长是八位
00000101 + 00000101 = 00001010 \space \space \space \space 00000101 \\ + 00000101 \\ =00001010 00000101+00000101=00001010
没问题,的得到的是 + 10 +10 +10.
再来算算 5 − 5 5 - 5 5−5
00000101 − 00000101 = 00000000 \space \space \space \space 00000101 \\ - 00000101 \\ =00000000 00000101−00000101=00000000
那么 ( − 5 ) + 5 (-5) + 5 (−5)+5 呢
10000101 + 00000101 = 10000000 \space \space \space \space 10000101 \\ + 00000101 \\ =10000000 10000101+00000101=10000000
欸,0 出现了两种表示方法。不行,会给以后的运算造成麻烦。
接着改,于是设计出了反码。
反码
[ X ] 反 = { X 0 ≤ X ≤ 2 n 2 n + 1 + X − 1 2 − n ≤ X ≤ 0 [X]_{\mathbb{反}}=\left\{\begin{array}{l} X \space \space \space \space\space \space\space \space\space \space\space \space \space\space \space \space\space \space \space\space \space \space0 \leq X \leq 2^n\\ 2^{n+1}+X-1 \space \space \space 2^{-n} \leq X \leq 0 \end{array}\right. [X]反={ X 0≤X≤2n2n+1+X−1 2−n≤X≤0
简单来说就是正数的反码就是原码,负数的反码就是符号位不变,其余各位按位取反。举个例子 : − 5 -5 −5 的反码就是 1010 1010 1010; + 5 +5 +5 的反码就是 0101 0101 0101
通过计算,发现0还是有两种表示方法,并且出现了一个问题就是有的直接加是不对的,还得有判断加两次。比如算 x = 1101 , y = − 1010 , x + y x=1101 , y= -1010, x + y x=1101,y=−1010,x+y. 这个例子你自己验证一下不再赘述,这样会发现第一次加完,得把符号位的进位位去掉再用加法加在第一次计算结果上,得到的才是正确答案。所以,又有了补码。
补码
[ X ] 补 = { X 0 ≤ X ≤ 2 n 2 n + 1 + X 2 − n ≤ X ≤ 0 m o d 2 n + 1 [X]_{\mathbb{补}}=\left\{\begin{array}{l} X \space \space\space \space \space\space \space \space\space \space \space\space \space \space0 \leq X \leq 2^n\\ 2^{n+1}+X \space \space \space 2^{-n} \leq X \leq 0 \end{array}\right. mod \space 2^{n+1} [X]补={ X 0≤X≤2n2n+1+X 2−n≤X≤0mod 2n+1
同样,正数的补码等于正数的原码,负数的补码等于反码 + 1.
比如 − 5 -5 −5 的补码就是 1011 1011 1011; + 5 +5 +5 的补码就是 0101 0101 0101
这样在计算0的表示方法就是单一的了。并且不难发现,计算减法的时候也可以用加法来代替了,不需要判断符号绝对值等的问题了。这样很方便只需要设计加法器就行了。
移码
前面说了半天,都是定点数,而要表示浮点数(就是小数点不固定的数)的接吗就要用移码的形式。
[ X ] 移 = 2 n + X − 2 n < X ≤ 2 n [X]_移=2^n + X \space \space -2^n < X \leq 2^n [X]移=2n+X −2n<X≤2n
实现起来就是数值与X数值位相同,但是符号位取反。
比如 − 5 -5 −5 的补码就是 0110 0110 0110; + 5 +5 +5 的补码就是 1010 1010 1010
在这里就不再深究这些表示方法是怎么来的了,若想知道自行百度。
定点与浮点数据表示
定点数:就是小数点固定的数,如果小数点固定再最后,就叫定点整数,再其他位置就是定点小数。
定点数的一个缺陷就是表示的数据范围不足。这一点很好理解。如果把小数点固定在某个位置,根据计算机的字长是固定的,所以,小数点后面的位数也是固定的,要想表示精确度很高(实际数据小数点后位数大于固定小数点后剩余的位数)的数,就没法表示。所以就有了不固定小数点的数据形式。
浮点数: 小数点的位置不固定的数。
浮点数表示
一般表示方法为 N = 2 E × M N=2^E \times M N=2E×M 其实就像十进制里的科学计数法一样。
其中,E就是阶码,E的位数决定数据的范围。这个参考十进制的科学计数法就不难理解,像是指数。 M是位数,决定数的精度,就是小数点后面有几位,是3.14啊还是3.1415926535啊等。
那在计算机里又是怎么表示的呢?计算机没法表示次方和称号呀。所以我们就把它省略掉。不能表示就不表示嘛。省掉之后就剩下EM。那2怎么也没了?当然,既然大家都是二进制数,不可能是别的进制,所以2就不用表示了。所以表示起来就是
E 1 E 2 ⋯ E n M 1 M 2 M 3 ⋯ M k E_1E_2\cdots E_n M_1 M_2 M_3 \cdots M_k E1E2⋯EnM1M2M3⋯Mk
举个例子:将 x = 2 − 01 × ( − 0.1110 ) x=2^{-01}\times (-0.1110) x=2−01×(−0.1110)表示成机器形式。假定用8位表示该数,阶码3位,位数5位(且均包含一位符号位), 假定阶码和尾数均采用补码。 − 0.1110 -0.1110 −0.1110的原码是 1.1110 1.1110 1.11