精华内容
下载资源
问答
  • 原码 反码 补码

    2021-04-30 14:50:53
    原码 反码 补码 对于 原码反码补码的学习记录 对于概念的描述也是基于个人理解做出的易于理解的表达方式,没有使用更严谨的数学公式定义 只针对整数 只针对加法 个人是从高位为符号位+低位为数值位的角度去...

    原码 反码 补码

    对于 原码、反码、补码的学习记录
    对于概念的描述也是基于个人理解做出的易于理解的表达方式,没有使用更严谨的数学公式定义

    只针对整数
    只针对加法

    个人是从高位为符号位+低位为数值位的角度去理解的
    但是不引入符号位这个概念也完全可以理解这三个概念,那就是另一种表述了,没有深入了解

    非科班出身,足够个人使用的个人理解,可能根本原理上会有理解错误,如有错误希望有大佬指正

    1.机器数和真值

    1.1 机器数

    数字在计算机中的二进制表示形式,有以下两个特点

    1. 具有符号位,即二进制中的最高位也就是最左边的一位表示符号, 0为正数, 1为负数(这是单符号位,还有双符号位不考虑)
    2. 其大小受字节长度限制

    例如, 在 Java 的 byte 类型(1个字节Byte,8个比特bit)中

    1 = [0000 0001] -1 = [1000 0001]

    1.2 真值

    真值就是机器码对应的真正的值,可以简单理解为使用正负号代替符号位

    1 = [0000 0001] 真值为 +000 0001
    -1 = [1000 0001] 真值为 -000 0001

    2.原码

    2.1 定义

    一个数的原码为符号位加上真值的绝对值
    即最高位为符号位,剩余位(数值位)为真值绝对值
    .
    原码中 0 会出现两种表示方式 1000 00000000 0000-0,+0

    原码是人可以直观理解的表示方式

    以 Java 的 byte 类型(8bit,最高位为符号位,剩余7位为数值位)来说

    原码取值范围为 -127 ~ 127, 存在符号位也参与计算, 0000 00001000 0000 只能都指向 0

    1 = [0000 0001]: 正数,最高位为0, 数值位为1(真值1的绝对值)的二进制 000 0001
    -1 = [1000 0001]: 负数,最高位为1, 数值位为1(真值-1的绝对值)的二进制 000 0001

    2.2 加法运算

    一般计算机中只有加法器而没有减法器,若设置单独的减法器则需要考虑结果的符号等一系列其他问题
    为了简化设计,最简单的思路就是把减法转换为加法

    1 + 1 = [0000 0001] + [0000 0001] = [0000 0010] = 2
    -1 + (-1) = [1000 0001] + [1000 0001] = [1 0000 0010] = -2 // 溢出了
    -1 + (-2) = [1000 0001] + [1000 0010] = [1 0000 0011] = -3 // 溢出了
    -1 + 1 = [1000 0001] + [0000 0001] = [1000 0010] = -2
    -1 + 2 = [1000 0001] + [0000 0010] = [1000 0011] = -3
    -0 + 0 = [1000 0000] + [0000 0000] = [1000 0000] = -0

    可以看到, 正数相加和负数相加是没问题的,而正数+负数则会出现问题

    其实原码也是可以通过一系列的运算规则来得到正确的结果的,但是需要额外判断符号位、溢出等情况,这样一来设计复杂程度将提高很多

    3.反码

    3.1 定义

    正数反码是其自身
    负数反码为原码的符号位不变, 数值位按位取反

    8位二进制反码取值范围为 -127 ~ 127, 存在符号位也参与计算但需要循环进位, 0000 0000 = +0 1000 0000 = -0

    1 = [0000 0001] = [0000 0001]
    -1 = [1000 0001] = [1111 1110]

    3.2 加法运算

    反码的加法涉及到一个 循环进位 的概念
    简单理解就最高位即符号位计算时如果发生进位则需要将进位送到最低位再次相加
    加法运算后结果仍为反码,但如果符号位为0则可以直接当做原码

    1 + 1 = 
            0000 0001  // 原/反
          + 0000 0001  // 原/反
          ------------
          = 0000 0010  = 2 // 符号位为0为正数,直接当原码
    
    -1 + 1 =
             1000 0001  // 原
           + 0000 0001  // 原
           ------------
         =   1111 1110  // 反
           + 0000 0001  // 反
           ------------
         =   1111 1111  // 符号位为1为负数,仍为反码
         =   1000 0000 = -0
    
    -1 + (-1) =
                1000 0001  // 原
              + 1000 0001  // 原
              ------------
            =   1111 1110  // 反
              + 1111 1110  // 反
              ------------
            = 1 1111 1100  // 符号位进位了
            =   1111 1101  // 循环进位 符号位为1为负数,仍然是反码
            =   1000 0010 = -2
    
    -1 + 2 =
             1000 0001  // 原
           + 0000 0010  // 原
           ------------
         =   1111 1110  // 反
           + 0000 0010  // 反
           ------------
         = 1 0000 0000  // 符号位进位了
         =   0000 0001 = 1 // 循环进位,符号位为0为正数,直接就是原码
    
    -0 + 0 =
             1000 0000  // 原
           + 0000 0000  // 原
           ------------
          =  1111 1111  // 反
           + 0000 0000  // 反
           ------------
          =  1111 1111  // 结果仍然是反码
          =  1000 0000 = -0
    
    0 + 0 =
            0000 0000 // 原/反
          + 0000 0000 // 原/反
          ------------
         =  0000 0000 = +0 // 原/反
    

    可以看到,反码的运算可以满足减法变换为加法,但是运算规则较为复杂(当前少量设备是基于反码进行运算的,没有深入了解)
    仍然不能忽略 +0-0

    4.补码

    4.1 定义

    补码的定义使用了同余的概念。
    正数的补码即为原码。
    负数的补码等于模 + 真值,其中模 = 2数值位数+1(也即可以表示数据的数量,双符号位(00为正,11为负)的同样遵循该方式)

    根据定义,可以得到一个结论 负数补码 = 真值 + 模 -> 负数补码 = 模 - 真值绝对值

    补码的意义是 按照这样一种编码规则(也就是表示正数、负数和零的约定),可以无需额外操作把减法运算变成加负数形式的加法运算
    从而在直接省略减法器的同时简化加法器的设计

    • 1.根据定义进行负数补码计算

    对于Java的byte类型, 数值位数=7,则模的值为 27+1 = 256, 即byte类型可以容纳的总数据量

    256 = [1 0000 0000]
    -1 = [1000 0001] 真值 = [-000 0001]
    -2 = [1000 0010] 真值 = [-000 0010]

    256 + (-1) =
                1 0000 0000   // 模256 1 0000 0000
               -   000 0001   // 真值     -000 0001
               -------------
                  1111 1111   // -1的补码
    
    256 + (-2) =
                1 0000 0000   // 模256 1 0000 0000
               -   000 0010   // 真值     -000 0001
               -------------
                  1111 1110   // -2的补码
    
    • 2.常用的一种通过反码计算负数补码的方法

    负数补码 = 原码符号位不变数值位按位取反 + 1 = 原码的反码 + 1
    负数原码 = (补码 - 1)后符号位不变数值位按位取反
    .
    在二进制中, 取反加一减一取反 是等价的, 这点也是有证明的,有兴趣可以看一下
    .
    因此负数补码还原成原码的计算可以变换成
    负数原码 = 补码符号位不变数值位按位取反 + 1 = 补码的反码 + 1
    可以看到, 这个过程和原码->补码的计算过程是一样的
    .
    因此我们可以得出一个比较绕的结论

    补码的补码就是原码或者补码和原码互为补码,严谨点说是 补码经过取反+1的操作后就是原码

    这也是由 取模同余 这一概念决定的

    -1 = 1000 0001  // 原码
         1111 1110  // 反码
         1111 1111  // 反码+1,即补码
    
    -2 = 1000 0010  // 原
         1111 1101  // 反
         1111 1110  // 反码+1,即补码
    

    注意 搜集资料时看到很多对反码的误解

    虽然补码可以通过反码+1的方式计算
    但并不代表反码就是原码和补码之间的过渡概念
    也不代表补码是在反码的基础上发展而来
    补码是根据取模同余设计出来的
    反码和补码拥有同样的地位
    反码也是有实际应用的,并不是补码的工具人
    只是恰好 补码 = 反码 + 1,而且这样也方便理解,计算机计算补码也是这个方法(使用定义来计算补码需要减法运算,而补码就是为了干掉减法)
    数学上有对于 补码 = 反码 + 1 的详细证明

    4.1.1 模和同余

    当两个整数除以同一个正整数,若得相同余数,则二整数同余
    或者
    两个整数 a,b,若它们除以整数 m 所得的余数相等,则称 a,b 对于模 m 同余
    .
    记作 a ≡ b (mod m)
    读作 a 与 b 关于模 m 同余

    需要注意 这里的余数应该使用 取模 运算获取,即计算中商应该向下取整

    Java/C 等语言的 % 运算符向零取整,即使商更接近 0, 应该叫做取余
    Python 等语言的 % 运算符向下取整,即使商更接近 -∞,是取模
    .
    两种取整方式在正数计算中没啥差别,但是负数计算结果就不一样了
    因此Java/C的%运算符不能用于计算这个余数
    Java中可以使用 Math.floorMod() 来进行取模运算

    -23 mod 12 == 1  // 商≈-1.92, 向下取整=-2, 则余数为 -23 - (-2) * 12 = -23 + 24 = 1
    -11 mod 12 == 1  // 商≈-0.92, 向下取整=-1, 则余数为 -11 - (-1) * 12 = -11 + 12 = 1
    1 mod 12 == 1
    13 mod 12 == 1
    25 mod 12 == 1
    

    -23,-11,1,13,25 都关于模 12 同余

    这一点可以借助钟表表盘来理解
    -23点 -11点 1点 13点 25点 在表盘上都是同一个位置,离12点都只有1格,只是顺时针/逆时针转了几圈的问题

    这也是补码运算不需要关心符号位的原因
    由于取模同余的性质,补码的取值范围(数轴)是圆形的,超限了也只是进入下一圈或上一圈
    而原码和反码这类直线数轴的,超限后就完蛋了

    虽然没有 -23点 的说法,理解含义即可

    4.2 加法运算

    4.2.1 同余加法

    补码的加法运算其实是依据以下性质进行的同余加法

    如果 a ≡ b (mod m), c ≡ d (mod m) 那么:
    a ± c ≡ b ± d (mod m)
    
    同样的乘法也有类似的性质
    a * c ≡ b * d (mod m)
    

    例如 对于byte类型 -1 ≡ 127 (mod 128) 1 ≡ 1 (mod 128)
    -1 + 1 ≡ (127 + 1) (mod 128) ≡ 128 (mod 128); 即 -1 + 1128 对于模 128 同余
    128 mod 128 = 0; 则 -1 + 1 的值应该是byte类型取值范围(-128~127)中对128取模=0的数,也就是0

    对于byte类型(8bit二进制数), -128 比较特殊

    1. 补码取值范围为 -128 ~ 127,存在符号位参与计算且不需用额外操作,也即补码的8位都可以作为数值位
    2. 解决了 +0 -0 的问题,因此相比于原码和反码空出了-01000 0000 的位置

    这个多出来的 1000 0000 用来干啥呢?

    1. 根据 4.1 补码定义, -128的补码 = -128 + 256(模) = 128
      数学上128的二进制表示为 1000 0000

    2. 根据补码的连续性,8位二进制总共可以表示256个数字
      根据补码表,发现按顺序向下推进,-128处的补码正好也是 1000 0000

      原码 反码 补码 真值
      0111 1111 0000 0000 0111 1111 +127
      0111 1110 0000 0001 0111 1110 +126
      原码-1… 反码-1… 补码-1… 真值-1…
      0000 0000 0111 1111 0000 0000 0
      1000 0001 1111 1110 1111 1111 -1
      原码-1… 反码-1… 补码-1… 真值-1…
      1111 1111 1000 0000 1000 0001 -127
      8位无法表示 0111 1111(实际没有反码) 1000 0000 -128

    上面两个情况计算出来的 -128 补码都是 1000 0000, 正好也是补码中多出来的位置
    因此将 -128 的补码规定为 1000 0000 完全是合情合理的
    而且 对应的原码在8bit下无法表示, 反码与 0 反码相同,所以 -128 没有原码和反码

    可以发现,即使没有原码和反码,补码也是可以存在的
    从这一点也可以得出,补码本质上是一个独立的概念,它不是以原码或者补码为基础存在的概念
    原码、反码、补码三者是为了解决不同问题分别发展出来的三个独立概念
    在数学上不能以概念出现的顺序来作为概念间关系的依据
    感兴趣可以看看对数指数两个概念的发展历史以及两者关系

    4.2.2 补码加法

    与反码的循环进位不同,补码的加法运算无需关注符号位的进位,可以将符号位的进位直接舍弃

    +1 = [0000 0001] = [0000 0001] = [0000 0001]
    -1 = [1000 0001] = [1111 1110] = [1111 1111]
    +2 = [0000 0010] = [0000 0010] = [0000 0010]
    0 = [0000 0000] = [0000 0000] = [0000 0000]

    1 + 1 =
            0000 0001  // 原/补
         +  0000 0001  // 原/补
         -------------
        =   0000 0010 = 2
    
    -1 + 1 =
             1111 1111  // 补
           + 0000 0001  // 原/补
           ------------
         = 1 0000 0000 // 溢出,直接抛弃
         =   0000 0000 = 0
    
    -1 + 2 =
             1111 1111  // 补
           + 0000 0010  // 原/补
           ------------
         = 1 0000 0001  // 溢出,直接抛弃
         =   0000 0001 = 1
    
    -1 + (-1) =
                1111 1111  // 补
              + 1111 1111  // 补
              ------------
            = 1 1111 1110  // 溢出,直接抛弃
            =   1111 1110  // 补
            =   1000 0001  // 之前提过 补码的补码就是原码
            =   1000 0010 = -2
    

    5.总结

    可以看到,计算机中大量应用了数学中的概念,可以说计算机就是在数学的基础上才发展起来的

    只可惜没学好数学,更没学过计算机领域相关的数学概念,导致现在稍微想深入学习就得一点一点的慢慢抠

    还有可能出现理解错误, 真是太难了

    展开全文
  • 这是这个主题的第三篇文章,前两篇介绍了这几种码的基本概念并深入详细的介绍了补码,这篇文章来具体说说「移码」。 00. 回顾 先来回顾一下移码是什么,简单说定义就一句话:**将补码符号位取反,即为移码。**乍一看...

    抛开复杂的理论,直探事物的本质。

    这是这个主题的第三篇文章,前两篇介绍了这几种码的基本概念深入详细的介绍了补码,这篇文章来具体说说「移码」。

    00. 回顾

    先来回顾一下移码是什么,简单说定义就一句话:将补码符号位取反,即为移码。乍一看,是不是有点懵,这到底在说什么呢?什么是移码?为什么是这么算?它能干嘛用?莫急,这些问题一个一个都会解决。

    相比于移码,应该使用补码的几率更高一些。因为移码主要用在浮点数的阶码中,用的较少。注意,这里又出来了一个新名词,「阶码」,关于这块的内容比较乱,会单独写一篇文章来说。而现在只需要记住一句话,移码的出现就是为了消灭负数

    01. 如何「消灭」负数

    先拿大家都熟悉的数轴举个例子。
    数轴

    如图,数轴上一共有 5 个点,分别为 -2、-1、0、1、2,其中有 2 个负数,所谓消灭负数,就是用 5 个非负数来表示这 5 个点,方法就是将 0 向左移动两个位置,如下。
    数轴

    很简单吧,这样一移动负数就被消灭了,而「移码」的计算就是这个道理,而将 0 向左移动 2 个位置就等同于将所有数字加 2,这个很好理解。很显然,移动的位数就是表示范围内负数的个数。

    02. 为什么是补码符号位取反?

    先明确一点:因为移码都是非负数,不需要符号位,所以,所有的二进制位都是用来表示数据的。

    接下来,根据上面得出的结论,我们亲自来算一算移码。为了便于计算,就拿 4 位二进制来举例。在计算机中,4 位二进制能表示的范围为 [-2^3, 2^3-1] = [-8, 7],其中负数的个数为 -1 到 -8,共 2^3 个,也就是 8 个,所以需要将 0 向左移动 8 个位置,即给每个数加上 8,如下。

         补码   +8  移码
    -8  [1000]  0 [0000]
    -7  [1001]  1 [0001]
    -6  [1010]  2 [0010]
    -5  [1011]  3 [0011]
    -4  [1100]  4 [0100]
    -3  [1101]  5 [0101]
    -2  [1110]  6 [0110]
    -1  [1111]  7 [0111]
     0  [0000]  8 [1000]
     1  [0001]  9 [1001]
     2  [0010] 10 [1010]
     3  [0011] 11 [1011]
     4  [0100] 12 [1100]
     5  [0101] 13 [1101]
     6  [0110] 14 [1110]
     7  [0111] 15 [1111]
    

    上面这样对比着看,应该很清晰了。经过计算得出的移码,刚好等于补码符号位取反,所以移码的定义就简化成了一句话:将补码符号位取反,即为移码。

    再说一个有点不好理解的方法,觉得啰嗦略过就好。除去首位的符号位不看,单看剩下的 3 位二进制,-8 到 -1 本身就符合从小到大的规律,而 0 到 7 也是如此,但 [0,7] 要大于 [-1,-8],强转成无符号数,用符号位的 0 和 1 两个值便可以区分原本的 8 个负数和 8 个非负数,最终就是将负数转化为了正数,将正数转化为了更大的正数

    结束

    至此,关于「原码 反码 补码 移码」主题的文章就告一段落了。

    段首写了这么一句话:「抛开复杂的理论,直探事物的本质」。我是这么理解这句话的,讲一样东西,只有把没什么基础的人都说明白了,说懂了,也不用过多的摆理论、套公式,这样才算是真的讲透彻了,话虽俗,理不俗。

    想看看前两篇文章的同学请点这里。

    「原码 反码 补码 移码」一探究竟(一)

    「原码 反码 补码 移码」一探究竟(二)


    欢迎关注同名公众号「码一八」获取更多内容,用技术改变生活!
    微信搜索「码一八」

    展开全文
  • 原码反码补码

    2017-02-17 17:27:00
    定义:正数的原码反码补码都一样,负数的反码除符号位都要取反,补码让它的反码加1。 1、原码就是转换的二进制数字,因为人可以知道左边首位是符号位,所以可以直观的用来计算 1+(-1)= 0; 2、计算机的计算为了...

    原码、反码和补码

    定义:正数的原码反码补码都一样,负数的反码除符号位都要取反,补码让它的反码加1。

    1、原码就是转换的二进制数字,因为人可以知道左边首位是符号位,所以可以直观的用来计算

    1+(-1)= 0;

    2、计算机的计算为了尽可能的简便,加入了反码的概念,但是会有一个问题,出现-0和0

    0000 0001((原码)) + 1000 0001 (原码)= 0000 0001(反码)+1111 1110(反码)= 1111 1111(反码)= 1000 0000(原码)= -0

    3、计算机为了解决(2、)出现的-0和0的问题,出现了补码

    0000 0001(反码)+1111 1110(反码)= 0000 0001(补码)+1111 1111(补码)= 1000 0000 (反码)= 0000 0000(原码)= 0

    补充:-1-127的结果应该是-128, 在用补码运算的结果中, [1000 0000] 就是-128. 但是注意因为实际上是使用以前的-0的补码来表示-128, 所以-128并没有原码和反码表示.(对-128的补码表示[1000 0000]补算出来的原码是[0000 0000], 这是不正确的)使用补码, 不仅仅修复了0的符号以及存在两个编码的问题, 而且还能够多表示一个最低数. 这就是为什么8位二进制, 使用原码或反码表示的范围为[-127, +127], 而使用补码表示的范围为[-128, 127].因为机器使用补码, 所以对于编程中常用到的32位int类型, 可以表示范围是: [-231, 231-1] 因为第一位表示的是符号位.而使用补码表示时又可以多保存一个最小值.

    以上转自:http://www.cnblogs.com/zhangziqiu/archive/2011/03/30/ComputerCode.html

    posted @ 2017-02-17 17:27 画个逗号给明天 阅读(...) 评论(...) 编辑 收藏
    展开全文
  • 在学习原码, 反码补码之前, 需要先了解机器数和真值的概念. 1、机器数 一个数在计算机中的二进制表示形式, 叫做这个数的机器数。机器数是带符号的,在计算机用一个数的最高位存放符号, 正数为0, 负数为1. 比如...

    Thursday,January 23,2020

    一. 机器数和真值

    在学习原码, 反码和补码之前, 需要先了解机器数和真值的概念.

    1、机器数

    一个数在计算机中的二进制表示形式, 叫做这个数的机器数。机器数是带符号的,在计算机用一个数的最高位存放符号, 正数为0, 负数为1.
    比如,十进制中的数 +3 ,计算机字长为8位,转换成二进制就是00000011。如果是 -3 ,就是 10000011 。
    那么,这里的 00000011 和 10000011 就是机器数。

    2、真值

    因为第一位是符号位,所以机器数的形式值就不等于真正的数值。例如上面的有符号数 10000011,其最高位1代表负,其真正数值是 -3 而不是形式值131(10000011转换成十进制等于131)。所以,为区别起见,将带符号位的机器数对应的真正数值称为机器数的真值。
    例:0000 0001的真值 = +000 0001 = +1,1000 0001的真值 = –000 0001 = –1

    二. 原码, 反码, 补码的基础概念和计算方法.

    在探求为何机器要使用补码之前, 让我们先了解原码, 反码和补码的概念.对于一个数, 计算机要使用一定的编码方式进行存储. 原码, 反码, 补码是机器存储一个具体数字的编码方式.

    1. 原码

    原码就是符号位加上真值的绝对值, 即用第一位表示符号, 其余位表示值. 比如如果是8位二进制:
    [+1]原 = 0000 0001
    [-1]原 = 1000 0001
    第一位是符号位. 因为第一位是符号位, 所以8位二进制数的取值范围就是:
    [1111 1111 , 0111 1111]

    [-127 , 127]
    原码是人脑最容易理解和计算的表示方式.

    2. 反码

    反码的表示方法是:
    正数的反码是其本身
    负数的反码是在其原码的基础上, 符号位不变,其余各个位取反.
    [+1] = [00000001]原 = [00000001]反
    [-1] = [10000001]原 = [11111110]反
    可见如果一个反码表示的是负数, 人脑无法直观的看出来它的数值. 通常要将其转换成原码再计算.

    3. 补码

    补码的表示方法是:
    正数的补码就是其本身
    负数的补码是在其原码的基础上, 符号位不变, 其余各位取反, 最后+1. (即在反码的基础上+1)
    [+1] = [00000001]原 = [00000001]反 = [00000001]补
    [-1] = [10000001]原 = [11111110]反 = [11111111]补
    对于负数, 补码表示方式也是人脑无法直观看出其数值的. 通常也需要转换成原码在计算其数值.

    三. 为何要使用原码, 反码和补码

    在开始深入学习前, 我的学习建议是先"死记硬背"上面的原码, 反码和补码的表示方式以及计算方法.
    现在我们知道了计算机可以有三种编码方式表示一个数. 对于正数因为三种编码方式的结果都相同:
    [+1] = [00000001]原 = [00000001]反 = [00000001]补
    所以不需要过多解释. 但是对于负数:
    [-1] = [10000001]原 = [11111110]反 = [11111111]补
    可见原码, 反码和补码是完全不同的. 既然原码才是被人脑直接识别并用于计算表示方式, 为何还会有反码和补码呢?
    首先, 因为人脑可以知道第一位是符号位, 在计算的时候我们会根据符号位, 选择对真值区域的加减. (真值的概念在本文最开头). 但是对于计算机, 加减乘数已经是最基础的运算, 要设计的尽量简单. 计算机辨别"符号位"显然会让计算机的基础电路设计变得十分复杂! 于是人们想出了将符号位也参与运算的方法. 我们知道, 根据运算法则减去一个正数等于加上一个负数, 即: 1-1 = 1 + (-1) = 0 , 所以机器可以只有加法而没有减法, 这样计算机运算的设计就更简单了.
    于是人们开始探索 将符号位参与运算, 并且只保留加法的方法. 首先来看原码:
    计算十进制的表达式: 1-1=0
    1 - 1 = 1 + (-1) = [00000001]原 + [10000001]原 = [10000010]原 = -2
    如果用原码表示, 让符号位也参与计算, 显然对于减法来说, 结果是不正确的.这也就是为何计算机内部不使用原码表示一个数.
    为了解决原码做减法的问题, 出现了反码:
    计算十进制的表达式: 1-1=0
    1 - 1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原= [0000 0001]反 + [1111 1110]反 = [1111 1111]反 = [1000 0000]原 = -0
    发现用反码计算减法, 结果的真值部分是正确的. 而唯一的问题其实就出现在"0"这个特殊的数值上. 虽然人们理解上+0和-0是一样的, 但是0带符号是没有任何意义的. 而且会有[0000 0000]原和[1000 0000]原两个编码表示0.
    于是补码的出现, 解决了0的符号以及两个编码的问题:
    1-1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原 = [0000 0001]补 + [1111 1111]补 = [0000 0000]补=[0000 0000]原
    这样0用[0000 0000]表示, 而以前出现问题的-0则不存在了.而且可以用[1000 0000]表示-128:
    (-1) + (-127) = [1000 0001]原 + [1111 1111]原 = [1111 1111]补 + [1000 0001]补 = [1000 0000]补
    -1-127的结果应该是-128, 在用补码运算的结果中, [1000 0000]补 就是-128. 但是注意因为实际上是使用以前的-0的补码来表示-128, 所以-128并没有原码和反码表示.(对-128的补码表示[1000 0000]补算出来的原码是[0000 0000]原, 这是不正确的)
    使用补码, 不仅仅修复了0的符号以及存在两个编码的问题, 而且还能够多表示一个最低数. 这就是为什么8位二进制, 使用原码或反码表示的范围为[-127, +127], 而使用补码表示的范围为[-128, 127].
    因为机器使用补码, 所以对于编程中常用到的32位int类型, 可以表示范围是: [-231, 231-1] 因为第一位表示的是符号位.而使用补码表示时又可以多保存一个最小值.

    四 原码, 反码, 补码 再深入
    计算机巧妙地把符号位参与运算, 并且将减法变成了加法, 背后蕴含了怎样的数学原理呢?
    将钟表想象成是一个1位的12进制数. 如果当前时间是6点, 我希望将时间设置成4点, 需要怎么做呢?我们可以:

    1. 往回拨2个小时: 6 - 2 = 4
    2. 往前拨10个小时: (6 + 10) mod 12 = 4
    3. 往前拨10+12=22个小时: (6+22) mod 12 =4
      2,3方法中的mod是指取模操作, 16 mod 12 =4 即用16除以12后的余数是4.
      所以钟表往回拨(减法)的结果可以用往前拨(加法)替代!
      现在的焦点就落在了如何用一个正数, 来替代一个负数. 上面的例子我们能感觉出来一些端倪, 发现一些规律. 但是数学是严谨的. 不能靠感觉.
      首先介绍一个数学中相关的概念: 同余

    同余的概念
    两个整数a,b,若它们除以整数m所得的余数相等,则称a,b对于模m同余
    记作 a ≡ b (mod m)
    读作 a 与 b 关于模 m 同余。
    举例说明:
    4 mod 12 = 4
    16 mod 12 = 4
    28 mod 12 = 4
    所以4, 16, 28关于模 12 同余.

    负数取模
    正数进行mod运算是很简单的. 但是负数呢?
    下面是关于mod运算的数学定义:

    上面是截图, "取下界"符号找不到如何输入(word中粘贴过来后乱码). 下面是使用"L"和"J"替换上图的"取下界"符号:
    x mod y = x - y L x / y J
    上面公式的意思是:
    x mod y等于 x 减去 y 乘上 x与y的商的下界.
    以 -3 mod 2 举例:
    -3 mod 2
    = -3 - 2xL -3/2 J
    = -3 - 2xL-1.5J
    = -3 - 2x(-2)
    = -3 + 4 = 1
    所以:
    (-2) mod 12 = 12-2=10
    (-4) mod 12 = 12-4 = 8
    (-5) mod 12 = 12 - 5 = 7

    开始证明
    再回到时钟的问题上:
    回拨2小时 = 前拨10小时
    回拨4小时 = 前拨8小时
    回拨5小时= 前拨7小时
    注意, 这里发现的规律!
    结合上面学到的同余的概念.实际上:
    (-2) mod 12 = 10
    10 mod 12 = 10
    -2与10是同余的.
    (-4) mod 12 = 8
    8 mod 12 = 8
    -4与8是同余的.
    距离成功越来越近了. 要实现用正数替代负数, 只需要运用同余数的两个定理:
    反身性:
    a ≡ a (mod m)
    这个定理是很显而易见的.
    线性运算定理:
    如果a ≡ b (mod m),c ≡ d (mod m) 那么:
    (1)a ± c ≡ b ± d (mod m)
    (2)a * c ≡ b * d (mod m)
    如果想看这个定理的证明, 请看:http://baike.baidu.com/view/79282.htm
    所以:
    7 ≡ 7 (mod 12)
    (-2) ≡ 10 (mod 12)
    7 -2 ≡ 7 + 10 (mod 12)
    现在我们为一个负数, 找到了它的正数同余数. 但是并不是7-2 = 7+10, 而是 7 -2 ≡ 7 + 10 (mod 12) , 即计算结果的余数相等.
    接下来回到二进制的问题上, 看一下: 2-1=1的问题.
    2-1=2+(-1) = [0000 0010]原 + [1000 0001]原= [0000 0010]反 + [1111 1110]反
    先到这一步, -1的反码表示是1111 1110. 如果这里将[1111 1110]认为是原码, 则[1111 1110]原 = -126, 这里将符号位除去, 即认为是126.
    发现有如下规律:
    (-1) mod 127 = 126
    126 mod 127 = 126
    即:
    (-1) ≡ 126 (mod 127)
    2-1 ≡ 2+126 (mod 127)
    2-1 与 2+126的余数结果是相同的! 而这个余数, 正式我们的期望的计算结果: 2-1=1
    所以说一个数的反码, 实际上是这个数对于一个膜的同余数. 而这个膜并不是我们的二进制, 而是所能表示的最大值! 这就和钟表一样, 转了一圈后总能找到在可表示范围内的一个正确的数值!
    而2+126很显然相当于钟表转过了一轮, 而因为符号位是参与计算的, 正好和溢出的最高位形成正确的运算结果.
    既然反码可以将减法变成加法, 那么现在计算机使用的补码呢? 为什么在反码的基础上加1, 还能得到正确的结果?
    2-1=2+(-1) = [0000 0010]原 + [1000 0001]原 = [0000 0010]补 + [1111 1111]补
    如果把[1111 1111]当成原码, 去除符号位, 则:
    [0111 1111]原 = 127
    其实, 在反码的基础上+1, 只是相当于增加了膜的值:
    (-1) mod 128 = 127
    127 mod 128 = 127
    2-1 ≡ 2+127 (mod 128)
    此时, 表盘相当于每128个刻度转一轮. 所以用补码表示的运算结果最小值和最大值应该是[-128, 128].
    但是由于0的特殊情况, 没有办法表示128, 所以补码的取值范围是[-128, 127]

    如有不足,谢谢大家帮忙指正!

    展开全文
  • 原码反码补码

    2017-06-12 03:58:00
    1. 总的概念 数在计算机中是以二进制形式表示的; 数分为有符号数和无符号数; 原码反码补码都是有符号定点数的表示方法; 无符号数全部按正数...2. 反码补码定义 正数: 原码=反码=补码 负数: 原码 反码 =...
  • 原码反码补码和移码

    千次阅读 2018-11-13 10:44:08
    书中关于原码反码补码和移码的定义如下(n是机器字长): 原码反码补码: 移码: 一. 机器数和真值 在学习原码, 反码补码之前, 需要先了解机器数和真值的概念. 1、机器数 一个...
  • leetcode求整数的反码补码以及Java移位运算符的概念Java整数类型原码反码补码移位运算符 左移(<<)leetcode求正整数补码Java代码 Java整数类型 在Java中定义整数有四种方式byte(8),short(16),int(32),long...
  • 机器数和机器数的真值在学习原码反码补码之前, 需要先了解机器数和真值的概念。1、机器数一个数在计算机中的二进制表示形式,叫做这个数的机器数。机器数是带符号的,在计算机用机器数的最高位存放符号,正数...
  • 本篇文章讲解了计算机的原码, 反码补码....一、机器数和真值在学习原码, 反码补码之前, 需要先了解机器数和真值的概念.1、机器数一个数在计算机中的二进制表示形式, 叫做这个数的机器数。机器数是...
  • 二进制原码反码补码

    万次阅读 多人点赞 2013-03-28 16:24:45
    在探求为何机器要使用补码之前, 让我们先了解原码反码补码概念.对于一个数, 计算机要使用一定的编码方式进行存储. 原码反码补码是机器存储一个具体数字的编码方式. 1.1模的概念 把一个计量单位称...
  • 原码反码补码简单介绍原码1.定义(百度)2.表达方式3.注意点反码1.定义2.表达方式3.注意点补码1.引入模的概念2.定义3.表达方式4.注意点比较 简单介绍 在计算机中,表达数值有两个基本特点: 1.计算机内部只能...
  • 计算机为什么要有原码反码补码的? :为了解决计算机负数表示与运算问题而引人了反码补码。 现在的计算机,只能识别1和0。所以计算机的内部运算采用...原码反码补码定义: 在计算机中所有的数字都是以补
  • 原码补码,真的很难学什么是机器数原码表示法补码表示法模运算补码定义特殊数据的补码表示补码原码之间的转换已知[ X ] 原 求[ X ] 补 :已知[ X ] 补 求[ X ] 原 :已知[ X ] 补 求[ -X ] 补 :反码表示法 ...
  • 注意:计算机实际上是按照补码进行存储的,对计算机来说没有原码反码这种东西,原码反码只是为了我们方便计算补码定义的一种概念。 一、原码 正数的原码就是它本身,负数的原码最高位为1。 如果用一个字节...
  • 很多朋友都知道计算机内部的数据通过二进制来储存和计算,但是一个小小二进制非要整一些花里胡哨(bushi)的东西,原码补码反码的一群东西,头大[石化]搞得我一脸懵。来自渣渣的咆哮可是又不能真的不学[泣不成声]日子...
  • 原码 补码 反码

    千次阅读 2010-03-11 08:55:00
    相信大家看到这个标题都不屑一顾,因为在任何一本计算机基础知识书的第一章都有他们的解释,但是在书上我们只能找到一些简单的定义,没次看过之后不久就忘了。最近论坛里有人问起这些概念,看到很多人的回复是以前看...
  • 闲扯原码反码补码 相信大家看到这个标题都不屑一顾,因为在任何一本计算机基础知识书的第一章都有他们的解释,但是在书上我们只能找到一些简单的定义,没次看过之后不久就忘了。最近论坛里有人问起这些概念,...
  • 补码表示法3. 反码表示法三种机器数小结4. 移码表示法 最近在看哈工大刘宏伟老师的《计算机组成原理》,总结其中关于有符号数的几种表示法,顺便感谢老师这么好的公开课。 首先先明确两个概念: 真值:带符号...
  • 闲扯原码反码补码 相信大家看到这个标题都不屑一顾,因为在任何一本计算机基础知识书的第一章都有他们的解释,但是在书上我们只能找到一些简单的定义,没次看过之后不久就忘了。最近论坛里有人问起这些概念,...
  • 相信大家看到这个标题都不屑一顾,因为在任何一本计算机基础知识书的第一章都有他们的解释,但是在书上我们只能找到一些简单的定义,没次看过之后不久就忘了。最近论坛里有人问起这些概念,看到很多人的回复是以前看...
  • 相信大家看到这个标题都不屑一顾,因为在任何一本计算机基础知识书的第一章都有他们的解释,但是在书上我们只能找到一些简单的定义,没次看过之后不久就忘了。最近论坛里有人问起这些概念,看到很多人的回复是以前看...

空空如也

空空如也

1 2 3 4 5 6
收藏数 101
精华内容 40
关键字:

原码反码补码概念定义