• 原码,反码,补码的关系和计算


    1:为什么会出现原码,反码,补码?

    首先,确定一点,计算机中的储存信息的方式是以二进制的形式进行存储的。
    而原码指的是对数字二进值的定点表示方法,之所以采取二进制来保存数据的原因是二极管只能表示两种状态,通或者不通,即0和1。

    在进行数字运算的时候,只要将10进制的数据转为2进制,就可以快捷的完成运算。只不过这种运算方式在涉及到负数运算时就会出现问题,举个例子。

    10进制运算:
    -1 + 2 = 1;
    
    二进制运算
    1001
    +
    0010
    |
    1011
    1011在转化为十进制为-3(最高位是1时表示负数)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    这样的结果明显不符合我们的认知,那么错在什么地方呢?
    原因在于我们使用二进制进行有符号运算时,会将最高位设置为符号位,来区分正数和负数,即将一个数据分为了符号部分和数值部分,举个例子

    1011-3)
    最高位的1是符号位,后三位是表示数值的数值位,分别设为a和b,合起来为a*b;
    我们在进行加减运算时,符号位是不参加运算的,只进行数值位的运算,比如
    1011
    + 
    0001
    =
    1100
    -3+1=4,这明显是错误的。原因就在于没有考虑到符号的影响,我们所有的计算都
    在数值位上进行:
    
    ```cpp
    设符号位是a,设数值位的值为b,十进制的值就是ab
    现在加上一个数,a*(b+2)=ab+2a;当a是1时,表达式的值为b+2,当a是-1时,表达式
    的值为-b-2,a的值影响到了整体的计算结果。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    1.1:引入反码,抵消符号位带来的影响

    从上面的计算已经知道,利用原码进行计算,会在正数和负数同时出现的运算上出现问题,本质的原因在于一个正数和一个负数进行运算时,符号位永远是1,导致原本做的加法变成了减法。在数学关系上,我们都知道负负得正,如果引入另外一个值,使得通过这个值既能反推出原码的值,又能用来做正确的数值计算,那么二进制运算的问题将得到完美解决。于是,反码应运而生。

    要想做到负负得正,想要抵消符号位带来的影响,那么反码的数值变化趋势就要与
    原码相反,在数学上表现为a+b=C,a代表原码的数值,b代表反码的数值,b如果变大
    ,a就会变小,两者相加得到常数。
    
    • 1
    • 2
    • 3

    1.1.1选什么当作常数呢?

    这个常数要能够针对不同的原码,变化出对应的反码。这里我们根据现在得到反码的规则去反推这个常数,反码是原码的符号位不变,其余位全部取反而得到的。

    比如
    1001的反码为1110,可以很容易的看出在符号位不参加运算时,原码和反码的数值位
    相加得到的结果就是数值位全部为1的值
    
    • 1
    • 2
    • 3

    1.2反码的计算还有问题?

    反码在进行负数的相关运算时,如果计算的结果没有超过0,是没有问题的,但是如果过超过0,就会出错,永远比正确结果小1

    考虑下面的计算:
    -1+2=110进制形式)
    将-12转化为二进制的反码进行运算
    1001-->1110(反码)
    0010-->0010(反码)
    结果为->0000,十进制下为0,如果考虑最高位的1,应该是-0,问题也就出在这个-0
    上
    请看下面这张对照表‘
    原码-------反码   十进制数值
    0000-------0000    +0
    1111-------1000    -0
    1001-------1000    -1
    1010-------1101    -2
    1011-------1100    -3
    1100-------1011    -4 
    1101-------1010    -5
    1110-------1001    -6
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    如果让-6加上3,你可以得到正确的-3,但是如果你让-6+7,你会得到0,本质在于,在反码中,0的表示方法有两种,换句话说,0数了两下。

    1.3补码出现,解决两个0问题

    你可能在C语言的教科书或者单片机的教科书中,看到过这样一段话
    一个8位的储存单元能够表示数值的大小范围是-128~127,你可能觉得很奇怪
    ,127还比较好理解,由于符号位的原因,真正用于表示数值的位只有7位,加起来就是2^7-1,但是-128是怎么算出来的呢?不应该是-127吗?造成这样困扰的罪魁祸首便是补码,在这张表中

    原码-------反码   十进制数值
    0000-------0000    +0
    1111-------1000    -0
    1001-------1000    -1
    1010-------1101    -2
    1011-------1100    -3
    1100-------1011    -4 
    1101-------1010    -5
    1110-------1001    -6
    我们注意到0出现了两次,只要让其中一个0失效,就可以解决所有问题了,不管是负
    数的运算,还是两个0问题,都解决了。解决方法也很简单,利用之前的思想,再引入
    一种新的编码方式,这种方式在反码的基础上规定只有所有位都是0才是0,其余数值
    全部在反码的基础上加一,这样,原来构成一种新的码,即补码,新的对照表如下
    原码-------反码----- 补码      十进制数值
    0000-------0000------0000        +0
    1000-------1111----- 0000        -0
    1001-------1110----- 1111        -1
    1010-------1101----- 1110        -2
    1011-------1100----- 1101        -3
    1100-------1011----- 1100        -4
    1101-------1010----- 1011        -5
    1110-------1001----- 1010        -6
    由于补码是在反码的基础上加1得到的,-128没有对应的原码和反码
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    总结

    1:反码由原码的符号位不变,其余位全部取反得到

    2:补码由反码加一得到

    3:计算机储存数字其实是储存了数字的补码,所有计算也是由补码进行。

  • 相关阅读:
    MST2102Q3 25A摩托车调压器控制芯片
    #php的pecl工具#
    nginx平滑升级解决 nginx 安全漏洞(CVE-2021-23017)和NGINX 环境问题漏洞(CVE-2019-20372)
    分享一下微信小程序怎么实现积分商城功能
    【YOLO系列改进NO.46】改进激活函数为ACON
    企业知识库构建:关于企业知识库及知识平台搭建的重要性!
    C语言动态内存管理
    双非渣渣的上岸之路!备战 60 天,三战滴滴侥幸收获 Offer
    WindowTabs 让决多窗口并排
    光纤快速连接器如何安装使用?
  • 原文地址:https://blog.csdn.net/qq_52320085/article/details/126368527