• 计算机中补码的数学运算逻辑及证明


    1. 问题

    我们知道,在计算机中是用补码来存放实际的正负数的,那么计算机为什么要用补码来存放数据,计算机课本中,那个补码 = 反码 + 1的公式又是怎么来的?

    要了解这些问题的答案,我们先要了解一些基本的知识,最基本的同余公式这里就不讲了,看本帖之前需要去离散数学或数论中了解下基本的同余运算即可。

    2. 计算机的字长和同余计算

    计算机的字长是指计算机运算时,能存放的最大数字的的位长,如我们常说的32位机,字长就是32位的,寄存器只有32bit,最多能放32个1,能表达的最大数字就是232 - 1

    当超过这个数字后,由于无法存储,会被计算机丢弃,同时会设置CPU的溢出标志位,这就是所谓的溢出

    为了简单,我们用8位机来做演示,即最大能表示的数字是28 - 1

    m = 28

    所以,计算机的计算 (a + b)时,实际上计算的是 (a + b) % m (mod m),超过m的部分都会被丢弃,只取余数的部分,即计算机中的计算实际都是一个模m的同余计算

    如 1000 0000 + 1000 0001 = 1 0000 0001

    由于最高位超出最大能够表示的数,多出的位将溢出丢弃,所以最后的结果为 0000 0001 = 1

    3. 补码的定义和计算

    设m > b >= 0,b为整数

    则b的补 b = m – b (注意,这里定义的是补,而不是补码,不要弄混了)

    由于有正负数,计算机中对正负数的补码进行了区分定义:

    1> 正整数b的补码为自身,即b的补码仍为b

    2> 负整数-b的补码为b的补,即b

    我们知道,a - b即可转化为 a + (-b),如果用补码来运算

    a – b = a + (-b)  (mod m) 在计算机中计算的是 a + b  (mod m)

    那么他们的同余吗(即他们模m后的值相等吗)?

    b = m – b

    ∴ a + b = a + (m – b)

              ≡ a – b (mod m)

    ∴ 将负数转化为补码进行计算后,仍然是成立的

    所以,计算机中用补码来储存所有的数后,就不需要增加减法器了,用加法器就可以代替计算减法,这样能节省电路设计,当然,这还只是其中的一个好处之一

    4. 负数的表示和运算

    前面讲了计算机中用补码来存储数字,我们知道,在8位机中,-1的补码为 1111 1111 = 255,那么在8位机中,这个数字即可以表示是-1的补码,也可以表示是255的补码,这就产生一个冲突了。

    为了解决这种冲突,计算机中,从可用的8位中挪用了一个最高位来区分正负数,即当最高位为1时,该数为负数,为0则表示正数

    这样,由于最高位被挪用,8位机在表示正负数时,就只有7位有效数字了,设m2 = 27 = 1000 0000 = 28 / 2 = m/2

    正负数仍用低7位的补码来表示,此时的模要换成m2了。

    如-1,1模m2的补码为 (m2-1) = 0111 1111,然后将最高位置为1,最终在计算机中表示为: 1111 1111(即oxFF)

    image

    image

    这时,我们前面定义的补码还有用吗?运算的法则还需要改变吗?

    1> a + b

    当 a + b 小于 m2时,不会向符号位进位,所以结果就是 a + b,没问题

    当2个正整数相加大于或等于m2时,就会向最高位进位,这时相对m2来说是溢出了,最高位会变为1,即(a+b)最后会得到一个负的结果,这个结果是无意义的,所以计算时要注意结果是否溢出

    测试代码:

    image

    设置带符号和10进制显示:

    image

    测试结果:

    从图中可以看出,100 + 100 = 200 = 0xC8 =1100 1000 = –56

    由于计算溢出,明显-56不是我们想要的结果

    2> a + (–b)

    当加上一个负数时,-b在计算机中的带符号的补码表示为: m2 + (m2 – b) = 2m2 – b = m – b   (m2 = 1000 0000,任何小于m2的数加上m2就相当于将其符号位变为1)

    ∴ a – b = a + (m – b)

             ≡ a – b (mod m)

    即带符号的补码在负数运算中,仍然有效

    但有个疑问,如果 a > b, a-b 为正数,计算完毕后符号位应该是0,当a < b时,a-b 为负数, 符号位应该是1,情况是这样的吗?

    4.2.1 当 a > b时

    ∵ a < m2

    ∴ a – b < m2 – b < m2

    ∴ (a – b)不会超过m2,即不会溢出到符号位,符号位仍会为0

    4.2.2 当  a < b时

    a – b ≡ m + a – b  (mod m)

           ≡ 2m2 + a – b   (mod m)

           ≡ (m2 – b) + m2  + a   (mod m)

    ∵ m2 >  b

    ∴ (m2 – b) > 0

    m > (m2 – b) + m2  + a > m2 

    ∴ a < b时,一定会向符号位溢出,即符号为一定会变为1

    同时,a – b ≡ a – b (mod m2)

    ∴ 溢出后,低7位的数与a-b仍是同余的

    所以,带符号位的补码运算,仍和不带符号位的补码运算规则一样,计算时将符号位带入计算,结果仍然一致,这样补码的第二个好处就出来了,即表示带符号的计算时,不用关心符号位。

    4.2.3 当 a == b时,以及a和b中有0的情况

    这个情况很简单了,就不证明了

    5. 补码和反码

    那么如何求一个数的补码呢,正数没问题,就是自身,但负数呢,上面已有简单的公式 –b → b = m – b, 但这里需要用到减法计算,而为了节省电路设计,我们用补码是为了省去减法器的,这就矛盾了,怎么办?

    看过书的同学已经知道,用反码来计算 : 补码 = 反码 + 1

    这个公式如何来的:

    1> 反码的定义

    我们知道,反码即是讲原来为0的位变为1, 为1的位变为0,

    我们也知道一个集合加上其反,就等于全集

    b + ~b = 1111 1111 = 28 – 1 = m - 1

    ∴ m = b + ~b + 1

    b = m – b = (b + ~b + 1) – b = ~b + 1

    这就是补码运算的著名公式的来源

  • 相关阅读:
    [转]大话企业级Android应用开发实战 用户界面
    [转]大话企业级Android应用开发实战 Activity
    logcat
    [转]大话企业级Android应用开发实战 2D图形
    戴尔R710服务器USC安装linux系统(转载)
    p4n 今天与朋友沟通支付云服务普及以及跨境电子商务的光辉前景
    atitit.研发管理标准化流程总结java开发环境与项目部署环境的搭建工具包总结
    atitit.产品console 日志的aticonsole 方案处理总结
    atitit. 研发管理如何根据自己的特挑选 产业、行业、职业、岗位与自己发展的关系
    Atitit.404错误解决标准流程and url汉字中文路径404错误resin4 resin chinese char path 404 err解决
  • 原文地址:https://www.cnblogs.com/organic/p/6486676.html
Copyright © 2020-2023  润新知