zoukankan      html  css  js  c++  java
  • 原码,反码,补码总结

    前言

    对于正数而言,原码,反码,补码都是一样的。但是对于负数而言,原码,反码,补码表示各有不同。

    原码 (Sign and Magnitude)

    用左边第一位来表示符号(Sign),0为正数,1为负数。其余位表示大小(Magnitude)。

    这里以用原码表示-56来举例:

    1. 写出大小的二进制表示
      56的二进制表示是0011 1000(默认8 bit)
    2. 把左边第一位改成1
      [-56]原 = 1011 1000

    其他例子:
    [+1]原 = 0000 0001
    [-1]原 = 1000 0001

    取值范围

    由于第一位是符号位, 所以用原码表示时,取值范围为:
    [111..11, 011..11]

    对于8 bit来说取值范围就是 [1111 1111 , 0111 1111] = [-127 , 127]

    原码表示负数的问题

    用原码表示负数时会出现几个问题:

    1. 该怎么表示0?
      这时候0可以有两种表示方法,0000 0000 (+0)和 1000 0000 (-0)

    2. 运算不方便
      考虑加法的三种种情况,可以知道对于每种情况,运算的方式都不同,这就造成了设计上的不方便

    • A+B (A是正数,B是正数)
      正数时正常加(Add Normal)
      [0001]原 + [0001]原 = [0002]原

    • A+B (A是正数,B是负数)
      此时要把加法变为减法,再拿数值相减
      11 + (-6) = [01011]原 + [10110]原 = 1011 - 0110 = 0101 = 5

    • A+B (A是负数,B是负数)
      此时要正常相加数值,最后要保留符号
      -3 + (-4)= [10011]原 + [10100]原 = 0011 + 0100 = 0111 = -7

    反码 (1's complement)

    关于反码有两种说法:

    第一种

    还是拿-56举例:

    1. 把大小转换成二进制 (Encode the positive value to binary)
      56的二进制表示是0011 1000
    2. 反转所有位 (Flip all bits)
      [-56]反 = 1100 0111

    第二种

    负数的反码是在其原码的基础上, 符号位不变,其余位取反.
    [+1] = [0000 0001]原 = [0000 0001]反
    [-1] = [1000 0001]原 = [1111 1110]反
    [-56] = [1011 1000]原 = [1100 0111]反

    反码表示负数的问题

    用反码表示负数时也会有跟原码一样的问题:

    1. 该怎么表示0?
      这时候0可以有两种表示方法,0000 0000 和 1111 1111

    2. 加法,减法,乘法,除法并不直观
      拿 (+1) + (-1)举例:
      我们期待 (+1) + (-1)= 0
      但是,(+1) + (-1)= 0000 0001 + 1111 1110 = 1111 1111 = -0

    补码 (2's complement)

    关于反码有两种说法:

    第一种

    还是拿-56举例:

    1. 把大小转换成二进制 (Encode the positive value to binary)
      56的二进制表示是0011 1000

    2. 反转所有位 (Flip all bits)
      [-56]反 = 1100 0111

    3. 加一 (Add one)
      [-56]补 = 1100 1000

    把补码转成整数:

    1. 反转所有位 (Flip all bits)
      1101 0100 -> 0010 1011

    2. 加一 (Add one)
      0010 1011 + 1 = 0010 1100

    3. 转换成大小
      0010 1100 = 44

    4. 加上负号
      [1101 0100]补 = -44

    第二种

    这边以-14的补码表示举例:

    1. 写成原码,改变符号位
      14 = 0000 1110
      [-14]原 = [1000 1110]

    2. 出符号位外,各个位取反
      [-14]反 = [1111 0001]

    3. 反码加一
      [-14]补 = [1111 0010]

    从补码推到原码
    以推导-69举例:
    [1011 1011]补

    1. 减一变成反码
      [1011 1010]反

    2. 除符号外取反
      [1100 0101]原 = (-)(1+22+26) = -69

    补码的范围

    [100..00, 011...1]

    也就是说[-1]补 = [1111 1111], 负数的取值范围变成了[1000 0000, 1111 1111]

    补码的好处

    1. 运算方便
      -56 + 12 = [1100 1000]补 + [0000 1100]补 = [1101 0100]补 = -44
      28 + (-26)= [0001 1100]补 + [1110 0110]补 = [1 0000 0010]补 = [0000 0010] = 2

    2. 拿补码和正数可以加一个溢出的零,0只有一个code表示
      1+-1 = [0000 0001]补 + [1111 1111]补 = [1 0000 0000]补 = [0000 0000] = 0

    ps: 这里溢出的1会被截断

    1. 能将字的最高有效位解释为负权
      [0001] = -0 * (2^3) + 0 * (2^2) + 0 * (2^1) + 1 * (2^0) = 0 + 0 + 0 + 1 = 1
      [1111] = -1 * (2^3) + 1 * (2^2) + 1 * (2^1) + 1 * (2^0) = -8 + 4 + 2 + 1 = -1
  • 相关阅读:
    Bioinfomatics dataset
    在Vue中使用sass和less,并解决报错问题(this.getOptions is not a function)
    axios获取文件流并下载文件
    原码,反码,补码总结
    leetcode_sql
    Mysql中Limit用法三个简单事例
    idea新建maven项目没有target文件夹
    重启mysql
    Windows下载安装netcat(nc)命令
    启动hive
  • 原文地址:https://www.cnblogs.com/qijunhe/p/13613116.html
Copyright © 2011-2022 走看看