zoukankan      html  css  js  c++  java
  • 机器数与位运算

    原码、反码、补码

    ​ 在计算机中,用来表示有符号数的机器数有三种,即原码、反码、补码三种表示方法均有“符号位”和“数值位”两部分

    1、符号位都是占据最高位,用0表示“正数”,用1表示“负数”
    2、数值位,三种表示方法各不相同
    
    1、正数:原码、反码、补码都一样
       真值:3
       原码:0000 0011   最高位为0,表示正数
       反码:0000 0011
       补码:0000 0011
    
    2、负数:原码、反码、补码不同
       真值:-3
       原码:1000 0011   最高位为1,表示负数
       反码:1111 1100   由原码演变而来,原码的符号位不变,数值位全部取反
       补码:1111 1101   在反码的基础上+1
    

    在计算机系统中,数值一律用补码来存储 !!! ​ 主要原因:使用补码,可以将符号位和其它位统一处理;同时,减法也可按加法来处理,需要注意的是两个用补码表示的数相加时,如果最高位(符号位)有进位,则进位被舍弃,处理完后我们如上图所示用补码反推出真值即可,例如计算机在计算8-3的时候,会这么做8+(-3),具体如下

    第一步:真值->原码->反码->补码
        真值:8
        原码:0000 1000  
        反码:0000 1000
        补码:0000 1000
    
        真值:-3
        原码:1000 0011  
        反码:1111 1100
        补码:1111 1101
    
    第二步:补码之间的运算,此处为相加
        8的补码:0000 1000
       -3的补码:1111 1101
      相加得补码:0000 0101 # 补码相加,高位有进位会被舍弃
    
    第三步:补码->反码->原码->真值
        上一步得到的补码结果:0000 0101
        符号位是0,为正数,那么就简单了,正数的原、反、补码都一样,所以一步到位
        补码->反码->原码:0000 0101
    
        原码->真值:5
    

    位运算符

    按位与&:两位全为1,结果才为1,否则为0
    按位或|:两位只要存在一个1,结果就为1,否则为0
    按位异或^:只有在两位不相同,即一个为0一个为1的情况下,结果才为1,否则为0
    << n:各二进制位全部左移n位,高位丢弃,低位补0
    >> n: 各二进制位全部右移n位,如果是正数,则高位补0,如果是负数则高位补1

    1.按位与&

    示例1:8 & -3
    
    第一步:真值->原码->反码->补码
        真值:8
        原码:0000 1000  
        反码:0000 1000
        补码:0000 1000
    
        真值:-3
        原码:1000 0011  
        反码:1111 1100
        补码:1111 1101
    
    第二步:补码之间的运算,此处为&
        8的补码:0000 1000
       -3的补码:1111 1101
        &得补码:0000 1000
    
    第三步:补码->反码->原码->真值
        上一步得到的补码结果:0000 1000
        符号位是0,为正数,那么就简单了,正数的原、反、补码都一样,所以一步到位
        补码->反码->原码:0000 1000
    
        原码->真值:8
    
    示例2:-8 & -9
    
    第一步:真值->原码->补码
        真值:-8
        原码:1000 1000  
        反码:1111 0111
        补码:1111 1000
    
        真值:-9
        原码:1000 1001  
        反码:1111 0110
        补码:1111 0111
    
    第二步:补码之间的运算,此处为&
       -8的补码:1111 1000
       -9的补码:1111 0111
        &得补码:1111 0000 
    
    第三步:补码->反码->原码->真值
        补码->反码
            补码结果:1111 0000 
            符号位是1,为负数,参照上图2的步骤
    
            补码->反码:-1,得到反码:1110 1111
    
        反码->原码:符号位不变,其余位取反,得到原码:1001 0000
    
        原码->真值:-16
    

    2.按位或|

    示例1:-8 | -9
    
    第一步:真值->原码->补码
        真值:-8
        原码:1000 1000  
        反码:1111 0111
        补码:1111 1000
    
        真值:-9
        原码:1000 1001  
        反码:1111 0110
        补码:1111 0111
    
    第二步:补码之间的运算,此处为|
       -8的补码:1111 1000
       -9的补码:1111 0111
        |得补码:1111 1111 
    
    第三步:补码->反码->原码->真值
        补码->反码
            补码结果:1111 1111 
            符号位是1,为负数,参照上图2的步骤
    
            补码->反码:-1,得到反码:1111 1110
    
        反码->原码:符号位不变,其余位取反,得到原码:1000 0001
    
        原码->真值:-1
    

    3.按位异或^

    示例1:-8 ^ -9
    
    第一步:真值->原码->补码
        真值:-8
        原码:1000 1000  
        反码:1111 0111
        补码:1111 1000
    
        真值:-9
        原码:1000 1001  
        反码:1111 0110
        补码:1111 0111
    
    第二步:补码之间的运算,此处为^
       -8的补码:1111 1000
       -9的补码:1111 0111
        ^得补码:0000 1111 
    
    第三步:补码->反码->原码->真值
        上一步得到的补码结果:0000 1111
        符号位是0,为正数,那么就简单了,正数的原、反、补码都一样,所以一步到位
        补码->反码->原码:0000 1111
    
        原码->真值:15
    
    示例2:^ -8 单独一个^代表取反的意思(适用于go,不适用于python)
    
    第一步:真值->原码->补码
        真值:-8
        原码:1000 1000  
        反码:1111 0111
        补码:1111 1000
    
    第二步:
       -8的补码:1111 1000
     ^取反得补码:0000 0111 
    
    第三步:补码->反码->原码->真值
        上一步得到的补码结果:0000 0111
        符号位是0,为正数,那么就简单了,正数的原、反、补码都一样,所以一步到位
        补码->反码->原码:0000 0111
    
        原码->真值:7
    

    4.向左位移<< n

    示范1:-8 << 3
    
    第一步:真值->原码->补码
        真值:-8
        原码:1000 1000  
        反码:1111 0111
        补码:1111 1000
    
    第二步:<< n 各二进制位全部左移n位,高位丢弃,低位补0
        补码:1111 1000
        <<3: 1100 0000
    
    
    第三步:补码->反码->原码->真值
        补码->反码
            补码结果:1100 0000
            符号位是1,为负数,参照上图2的步骤
    
            补码->反码:-1,得到反码:1011 1111
    
        反码->原码:符号位不变,其余位取反,得到原码:1100 0000
    
        原码->真值:-64
    

    5.向右位移>> n

    示范1:-8 >> 3
    
    第一步:真值->原码->补码
        真值:-8
        原码:1000 1000  
        反码:1111 0111
        补码:1111 1000
    
    第二步:>> n 各二进制位全部右移n位,如果是正数,则高位补0,如果是负数则高位补1
        补码:1111 1000
        >>3: 1111 1111
    
    
    第三步:补码->反码->原码->真值
        补码->反码
            补码结果:1111 1111
            符号位是1,为负数,参照上图2的步骤
    
            补码->反码:-1,得到反码:1111 1110
    
        反码->原码:符号位不变,其余位取反,得到原码:1000 0001
    
        原码->真值:-1
    
    示范2:8 >> 3
    
    第一步:真值->原码->补码
        真值:8
        原码:0000 1000  
        反码:0000 1000
        补码:0000 1000
    
    第二步:>> n 各二进制位全部右移n位,如果是正数,则高位补0,如果是负责则高位补1
        补码:0000 1000
        >>3: 0000 0001
    
    
    第三步:补码->反码->原码->真值
        上一步得到的补码结果:0000 0001
        符号位是0,为正数,那么就简单了,正数的原、反、补码都一样,所以一步到位
        补码->反码->原码:0000 0001
    
        原码->真值:1
    
    示范3:-300 >> 8
    
    第一步:真值->原码->补码
        真值:-300  
        原码:1000 0001 0010 1100 # -300 已经超过了8位二进制能表示的范围,需要用16位表示
        反码:1111 1110 1101 0011
        补码:1111 1110 1101 0100
    
    第二步:>> n 各二进制位全部右移n位,如果是正数,则高位补0,如果是负责则高位补1
        补码:1111 1110 1101 0100
        >>8: 1111 1111 1111 1110
    
    
    第三步:补码->反码->原码->真值
        补码->反码
            补码结果:1111 1111 1111 1110
            符号位是1,为负数,参照上图2的步骤
    
            补码->反码:-1,得到反码:1111 1111 1111 1101
    
        反码->原码:符号位不变,其余位取反,得到原码:1000 0000 0000 0010
    
        原码->真值:-2
    

    扩展

    1.将一个数左移 n 位,相当于乘以了 2 的 n 次方,右移n位,相当于除以2的n次方取整
    10 << 3 等同于10 * 2^3 
    10 >> 3 等同于10 / 3
    
    2.判断奇偶
    我们可以利用 & 运算符的特性,来判断二进制数第一位是0还是1。
    用if ((a & 1) == 0) 代替 if (a % 2 == 0)来判断a是不是偶数。
    
  • 相关阅读:
    十八、分页查询
    十七、oracle的权限和角色
    十六、同义词(synonyms)
    十五、序列
    十四、禁用与启动约束
    十三、修改表时添加约束
    十二、约束
    十一、修改表格
    十、事务(Transaction)
    Windows 远程连接后,自动断开,所有程序都自动关闭(待验证,待更新)
  • 原文地址:https://www.cnblogs.com/chenwenyin/p/12497713.html
Copyright © 2011-2022 走看看