数字在计算机中的表示,补码方案

数字在计算机中的表示

    数字是以二进制方式存储的,计算机的位(bit)只能存储0或1两种状态,对应的是有电,无电两种物理状态。
考虑7这个数字,很容易的想到用二进制数字111表示。考虑有一个4位的存储器,则存储器的物理状态为: 

+---+---+---+---+        +------+------+------+------+
| 0 | 1 | 1 | 1 |   ==>  | 无电 | 有电 | 有电 | 有电 | 
+---+---+---+---+        +------+------+------+------+   

    计算加法的有专门的“加法器”电路来实现。“加法器”就是输入3,4,得到结果7这样的一个逻辑电路。
如果要引入减法,必然要引入负数才实用,否则 3 - 5 = ?将变得没有意义。负数如何表达呢?
考虑-7这个数字,如何编码存储呢?很容易的想到,在4bit的存储器中,占用最高的数字位(bit3),当成符号位。1表示负号,0表示正号。

-7可以如此编码:
+---+---+---+---+       
| 1 | 1 | 1 | 1 |   
+---+---+---+---+   

    此种编码方案,被称为sign and magnitude符号和量值法(中文专业词汇:原码) 。 
此方案有明显的缺点。首先要特殊关照符号位,就像初中学生学代数那样,每一次计算都要考虑符号位。
其次是要设计“减法器”电路,增加了硬件成本。

    总之,我们需要用其它方案替代。替代方案就是two's complement二的补数方案(中文专业词汇:补码)
还有一个one's complement一的补数方案(中文专业词汇:反码),也被废弃不用。因为我们不是搞计算机考古专业的,
不需要考究编码方案的变更历史轨迹,就直接一笔带过。是传统科班教学的一个很大的弊端,就是喜欢考古,拐弯抹角,让学生
云里雾里不知所以然。

    考虑一个钟表,能显示0点,1点,2点,... 10点,11点。这个钟表当前在0点,回拨2小时,与正拨10小时是等价的。
可以闭上眼睛想象一下,的确如此。而初中代数就讲了,减一个整数2与加-2是一回事。在钟表这个语境里,加-2,又与+10是一回事。
综合起来,N - 2 =等价于= N + 10。相同的现象还发生在[1,11],[2,10],[3,9],[4,8],[5,7],[6,6]这些数对里。发现有个规律,[m,n]
m+n=12,这个12被称为模。钟表是模为12的计数系统。

现在来验证一下:6 - 2 = 6 + (-2) = 6 + 10 = 16 - 12 = 4   
补数理论解决减法变加法的问题。但是有个烦人的减12怎么破,暂时放一边?

现在推广到计算机的数字系统。

考虑一个4bit的计数系统,可以表示的范围是:[0,15], 使用[1,7]区间为正数编码;为使用[8,15]这个区间为负数编码。

表:4bit的补码表
+-------+--------+--------------+
| 2进制 | 十进制 |  表示的编码  |
+-------+--------+--------------+   
| 0000  |      0 |         0    |
+-------+--------+--------------+ 
| 0001  |      1 |         1    |
+-------+--------+--------------+ 
| 0010  |      2 |         2    |
+-------+--------+--------------+ 
| 0011  |      3 |         3    |
+-------+--------+--------------+ 
| 0100  |      4 |         4    |
+-------+--------+--------------+ 
| 0101  |      5 |         5    |
+-------+--------+--------------+ 
| 0110  |      6 |         6    |
+-------+--------+--------------+ 
| 0111  |      7 |         7    |
+-------+--------+--------------+ 
| 1000  |      8 |        -8    |
+-------+--------+--------------+ 
| 1001  |      9 |        -7    |
+-------+--------+--------------+ 
| 1010  |     10 |        -6    |
+-------+--------+--------------+ 
| 1011  |     11 |        -5    |
+-------+--------+--------------+ 
| 1100  |     12 |        -4    |
+-------+--------+--------------+ 
| 1101  |     13 |        -3    |
+-------+--------+--------------+ 
| 1110  |     14 |        -2    |
+-------+--------+--------------+ 
| 1111  |     15 |        -1    |
+-------+--------+--------------+ 

这里有个边界值1000应该表示成8还是-8呢?在数学上,把1000为8的编码完全正确,同理把1001为9编码也完全没问题。
但是在计算机设计的方便考虑,特意选取首位为1的那些编码,是负数的编码。因此1000被人为的选择成为-8的编码。
 
现在我们验证一下这套编码方案:

例1:3 - 7 = 3 + 9 = 12             验证成功,12恰好是-4的编码

想的是很美好,这里还有个技术问题要解决。如何计算-7对应的编码?总是不能每次查表吧?如何是64位的整数如何查表?
这就要用公式法了,补数的计算公式:N` = 2^n - N。这个公式有乘方,还有减法,再说了计算机没有减法器电路呀!!
我们需要一个速算算法,就是直接走捷径的开挂算法。还是以4bit计数系统为例。

∵ 2^4 = (8+4+2+1) + 1   (注:二进制10000 = 1111 + 1)

∴ 2^4 - 1 = 8+4+2+1

∴ 2^4 - 1 = 1*2^3 + 1*2^2 + 1*2^1 + 1*2^0    ①式

假设一个数N,用二进制表示为ABCD,则N用十进制表示为:∴ N = A*2^3 + B*2^2 + C*2^1 + D*2^0   ②式

①式 - ②式

2^4 - 1 - N = 1*2^3 + 1*2^2 + 1*2^1 + 1*2^0 - (A*2^3 + B*2^2 + C*2^1 + D*2^0)

∴ 2^4 - 1 - N = (1 - A)*2^3 + (1 - B)*2^2 + (1 - C)*2^1 + (1 - D)*2^0   ③式

∴ N` = 2^4 - N = (1 - A)*2^3 + (1 - B)*2^2 + (1 - C)*2^1 + (1 - D)*2^0 + 1    ④式

④式告诉了我们如何求一个数N的补数N`的开挂算法:由于A,B,C,D无非是0或1,则1-X等于求X的bit反,就是1的反是0,0的反是1。
设A,B,C,D四个位的反依次是A`,B`,C`,D`  则:N` = (A`B`C`D`) + 1  ⑤式。

现在根据公式⑤,设计一个算法来找到数N补码编码: 

step1:确定字长,比如4位字长。初始化为全0

step2:如果是N是正数,则N` = N的二进制值,填入word。

step3: 如果N是负数,则取绝对值|N|, 一般来说,根据计算机输入,是可以发现负号的
       例如:['-','3','\0']这个输入字符串,可以用算法把3提取出来,就得到了|N|=3

    step3.1 求|N|的补数, 先确定|N| = ABCD 二进制表示
    step3.2 取反加1,N` = (A`B`C`D`) + 1

我们需要明白,求补码和求补数的区别联系。这样当我们需要知道1101这个编码对应是多少时,才有了思路。
1101假设是一个数的补码编码,则把它看成一个正整数为13,其对应的补数为3,则1101代表了-3,这样才能输出['-,','3','\0']

例2:3 - 1 = 3 + 15 = 18 - 16 = 2   验证成功,2恰好等于3-1
           
这里又有个技术问题要解决,18 - 16怎么破?计算机没有减法器呀?

看一下18的二进制值10010,放在4bit的计数系统里:
      +---+---+---+---+       
溢出1 | 0 | 0 | 1 | 0 |   
      +---+---+---+---+  
可以看到最高位1是无处安放的,它被抛弃了。而被抛弃的这个1的价值正好是16,通过自然的溢出,帮助我们做了减16。

例3:3 - (-4) = 7

-4的补码在计算机中等效于12, 则3-(-4)看成 3 - 12,看成3+(-12),看成 3 +4
所以,减去一个数,等效于加上他的补数。

    另外,按照课本背诵原码,反码,补码之间的转换关系,是没有任何实际帮助的,只能背离实际工作场景越来越远。
    现在做一个本课程的小测试:在一个32位的计数系统中,0xFFFFFFFF表示什么?
    答:∵ 2^32 - 1 = 0xFFFFFFFF
           且 2^32 - 1是1的补数
        ∴ 0xFFFFFFFF是-1的补码编码

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值