深入理解计算机系统cp2:定点数的表示和运算

深入理解计算机系统cp1:存储单位、数制、编码 中解释了字符编码,我们知道了计算机是怎么把字符转化为二进制的;本文将解释数字编码,介绍计算机如何把数字转化为二进制,以及相关的运算问题。

1.定点数的表示

1.1 无符号数

  • 定义:无符号数就是没有体现正负号的数(这意味着所有的无符号数实际上都是正数),整个机器字长的全部二进制位均为数值位,没有符号位。以 108D 为例,它对应的二进制数是 1101100 ,这实际上也就是它的无符号数,可以看到所有的位都是数值位。
  • 表示范围:以八位二进制数为准,范围就是 0000000011111111 ,也就是 0 到 255

1.2 有符号数

  • 定义:有符号数就是有体现正负号的数,整个机器字长的全部二进制位中,最高位作为符号位,0 表示正数,1 表示负数,其余位则是数值位。依然以 108D 为例,它对应的二进制数是 1101100 ,而对应的有符号数则要在最前面加上符号位 0,即它的有符号数是 01101100 .

  • 表示范围:以八位二进制数为准,范围应该是从负数到正数,即从 1111111101111111 ,也就是 -127 到 127

1.2.1.真值和机器数

  • 真值:就是带有正负号的实际十进制数,比如上面例子中, +108D 就是真值
  • 机器数:机器数就是一个数在计算机中的二进制表示形式,注意 机器数是由符号位和数值位 构成的,比如上面例子中, 01101100 就是机器数。

-156D (真值)= 110011100B (机器数)

1.2.2.原码、反码、补码和移码

(1)原码表示法

简单点理解,原码就是符号位加上真值(二进制)的绝对值,同时用逗号将符号位和数值位隔开。比如,+1 就是 0,0000001 ,-1 就是 1,0000001

原码的特点是简单、直观,但是原码在进行加法运算的时候会出现问题。正数加正数或者负数加负数是正常的,但是正数加负数就会出错。比如我们现在想要计算 -1+3,我们心想:-1 是 10000001 ,+3 是 00000011 ,加起来得到的是 10000100 ,所以结果是 -4,但 -1+3 应该是等于 2,所以这个结果是错的。我们发现,本来应该做的是加法运算,但实际上变成了减法运算(-1-3=-4)。

我们首先想到,可以通过将“正数加负数”转化为“正数减正数”来手动纠正这个错误。上面的例子就变成 0000001100000001 ,结果是 00000010 ,也就是 2,这个结果是正确的。

但是每次都这样手动转化,计算起来还是太麻烦了。于是我们接着想:有没有一种方法,可以让“正数加负数”中的 负数等价于一个正数 ,从而确保始终进行的是相加操作呢?

于是这时候就引出了补码的概念。

(2)补码表示法

  • 补数和模:理解补码之前,我们先来理解两个概念: 补数

    拿时钟举例,想要从10点拨到8点,有两种做法,一种是逆时针拨2个单位,记作-2;一种是顺时针拨10个单位,记作+10,这两种操作是等效的(有点 负数等价于一个正数 的意思)。这时候我们就说,-2 是 +10 以 12 为模的补数,记作 -2≡+10(mod 12) ,同理,-5 相当于 +7,-4 相当于 +8。

  • 那么怎么基于补数和模的概念将“正数加负数”转化为“正数加正数” —— 即怎么令 负数等价于一个正数 呢?假设我们现在有一个寄存器可以存放四位二进制数(此时,模为16),我们想要让 1011 变成 0000 ,最容易想到的办法就是 1011-1011=0000 ,注意这里是正数加负数。想要变成正数加正数,就要找到等价于 -1011 的正数, -1011 就是 -11,-11 以 16 为模的补数就是 +5,+5 就是 +0101 ,这个正是我们要找的那个等价正数,因此这时候, 1011-1011 变成了 1011+0101 ,其结果是 10000 ,不要忘了寄存器只能存放四位,所以结果其实是 0000 ,恰好与我们“正数加负数”时得到的结果无异。

  • 接着引入补码的概念:

    • 对于正数:正数的补码和原码相同;
    • 对于负数:负数的补码等于其原码在保持符号位不变的情况下,其余各位取反,末位加一(取反加一)。 注意 ,补码的补码等于原码,这可以用来根据补码求原码。
    • 也可以用下图方法计算补码:

还是上面的例子, 1011-1011 ,也就是11-11,我们考虑+11和-11,+11的原码=补码= 01011 ,-11的原码是 11011 ,因此补码是 10101 ,那么 01011+10101 就会等于 100000 ,因为寄存器是五位的,把前面的1去掉,那么结果就是 00000 ,也就是0,和上面的运算结果一致。

(3)反码表示法

反码很好理解:

  • 正数:反码等于原码等于补码;
  • 负数:反码等于原码保持符号位不变的情况下其余各位取反。也就是说,补码=反码+1
  • 反码的反码等于原码,这可以用来根据反码求原码。

(3)移码表示法

补码存在的问题是,仅从补码本身来看,很难比较两个数的大小,为此引入了移码的概念。移码指的是在真值(二进制)的基础上加上一个偏移量,通常这个偏移量是2^n。其中,n是数值位的位数。

例如,对于 -10101 ,其移码是 2^7+(-10101)=10000000+(010101)=0,1101011