机器数与位运算

原码、反码、补码

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

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是不是偶数。
posted @ 2020-03-15 15:12  风亦缘^_^  阅读(536)  评论(0编辑  收藏  举报