• 关于计算机中补码的理解


    之前写过一篇文章,总结计算机中全加器的原理,使用全加器可以方便的对两数进行相加运算。

    但是如何处理减法呢?

    这里就要使用补码了。那何为补码呢,之前学习的时候一直没有仔细思考,这个补字的含义。其实这里的补就是另一种状态的对立。想象一下如果一面墙破了一个洞,我们要把它补起来。那么这里的补,其实就是破了洞的墙和缺块的地方共同组成了一面完成的墙。

    在日常生活中,我们使用十进制的减法时,常常遇到要借位进行相减的时侯,如253减去176。此时个位和百位上的数字不够减,就需要借位了。有时为了快速的计算,我们常常会这样处理,即253 + 1000 - 176- 1000, 然后再将1000 拆解成999 + 1 ,于是原式子就变成了 253+ 999 - 176+ 1 - 1000,这样使用999 - 176就不会发生借位了,各位上的减法都是10以内的。同时,最后的加 1 和减去1000都比较容易计算。这样一个减法通过变成两个加法和两个减法来简化计算的难度了。

    其实在 999 - 176= 823这个等式中,我们称823是176对999的补数。

    在计算机中处理二进制的时候也借鉴了这样的思想。 因为计算机二进制只有两个数,如果求对1的补数,1就是0,0就是1,相当于取反了。 这样计算起来就比较容易,在逻辑电路上实现也很方便,直接用非门就可以了。

    下面用补码的形式计算一下253减去176,过程如下:

    过程溢出位第8位第7位第6位第5位第4位第3位第2位第1位
    253二进制11111101
    176二进制10110000
    176补码01001111
    253与176
    补码相加
    101001100
    253与176
    补码相加在加1
    101001100
    上一行结果减
    100000000
    1001101

    最终的结果为 1001101 也即十进制的77。 从上表格看,如果使用补码的话可以方便的将计算过程转化为加法。

    上述的分析过程只是使用了补码来简化了减法的运算过程,那么如何用补码来表示负数呢?

    以8位的二进制为例,每个二进制位上有两种状态,总共可以表示2的8次方个数,即从0000-0000到1111-1111,也即十进制中的0到255。为了表示负数,将第一个二进制位用来表示符号,剩余的二进制位表示数值大小。由于少了一位表示数值,此时数值的表示范围就减小了一半,变成了 000-0000 到 111-1111了,也即十进制中的0到127 (剩余的一半其实就是以补码形式表示的负数了)。

    用补码表示时,规定首位为0时表示正数,首位为1时表示负数。

    对于正数,其补码等于本身,无需改变,但是负数需要将对应的正数按位取反,然后加1得到补码。 比如-125,如下表格列出计算过程。

    十进制-125
    125的二进制0111 1101
    125的反码表示1000 0010
    加 1,得到-125的补码1000 0011

    得到了补码后,如何将补码转化成对应的十进制数呢?

    此时,可以先按照正常的二进制转化成十进制的方式来,只是首位的计算要根据符号位取对应的正负。 如-125的补码为 1000 0011,可以进行如下的计算转化成十进制

    -1 * 2^7 + 1 * 2^1 + 1 = -128 + 2 + 1 = -125

    下表是部分8位二进制补码表示的编码,平时可以用来参考。

    二进制十进制转化过程
    1000 0000-128-1 * 2^7
    1000 0001-127-1 * 2^7 + 1
    1000 0010-126-1 * 2^7 + 1 * 2^1
    1000 0011-125-1 * 2^7 + 1 * 2^1 + 1
    1000 0100-124-1 * 2^7 + 1 * 2^2
    1111 1101-3如上,展开为 -127 + 64 + 32 + 16 + 8 + 4 + 1
    1111 1110-2如上,展开为 -127 + 64 + 32 + 16 + 8 + 4 + 2
    1111 1111-1-127 + 64 + 32 + 16 + 8 + 4 + 2 + 1
    0000 00000
    0000 000111 * 2^0
    0000 001021 * 2^1
    0000 001131 * 2^1 + 1
    0111 11001241 * 2^6 + 1 * 2^5 + 1 * 2^4 + 1 * 2^3 + 1 * 2^2
    0111 11011251 * 2^6 + 1 * 2^5 + 1 * 2^4 + 1 * 2^3 + 1 * 2^2 + 1 * 2^0
    0111 11101261 * 2^6 + 1 * 2^5 + 1 * 2^4 + 1 * 2^3 + 1 * 2^2 + 1 * 2^1
    0111 11111271 * 2^6 + 1 * 2^5 + 1 * 2^4 + 1 * 2^3 + 1 * 2^2 + 1 * 2^1 + 1 * 2^0

    1开头全部表示的是负数,0开头表示的是负数。同时,将上述表格中的负数补码先取反在加1可以得到对应的正数。

    虽然在平时的编码过程中,好像没有直接使用到补码,但是理解了补码之后或许能更好的理解各种数据长度的表示范围及其他计算机基础。一点点的清理学习路上的障碍,后面的学习之路才会更通畅。

  • 相关阅读:
    LabVIEW软件开发任务的工作量估算方法
    第一章操作系统引论
    Spark基础
    在CentOS下安装MySQL
    c++ 变量、常量、基本数据类型
    655. 输出二叉树
    YARN线上动态资源调优
    时域分析瞬时自相关算法、频域分析复倒频分析法、调制域分析过零检测算法以及时频分析小波换算法matlab仿真
    o.s.b.d.LoggingFailureAnalysisReporter 错误解决方法
    SSL证书报错类型及解决方法
  • 原文地址:https://blog.csdn.net/honeysx/article/details/125420214