zoukankan      html  css  js  c++  java
  • 位运算之左移右移运算之详解

    先看如下一段左移右移的代码及其结果:

    代码
    #include "stdio.h"

    char leftshift(char i, int n)
    {
    if(n < 0)
    return -1;
    return i<<n;
    }

    char rightshift(char i, int n)
    {
    if(n < 0)
    return -1;
    return i>>n;
    }

    int main()
    {
    //leftshift
    char a1 = 127;
    char a2 = -1;

    for(int i = 1; i <= 8; i++)
    printf(
    "%d<<%d = %d;\n", a1, i, leftshift(a1,i));

    for(i = 1; i <= 8; i++)
    printf(
    "%d<<%d = %d;\n", a2, i, leftshift(a2,i));

    //rightshift
    a1 = 127;
    a2
    = -128;

    for(i = 1; i <= 8; i++)
    printf(
    "%d>>%d = %d;\n", a1, i, rightshift(a1,i));

    for(i = 1; i <= 8; i++)
    printf(
    "%d>>%d = %d;\n", a2, i, rightshift(a2,i));

    return 0;
    }

    结果为:

    结果
    127<<1 = -2;
    127<<2 = -4;
    127<<3 = -8;
    127<<4 = -16;
    127<<5 = -32;
    127<<6 = -64;
    127<<7 = -128;
    127<<8 = 0;

    -1<<1 = -2;
    -1<<2 = -4;
    -1<<3 = -8;
    -1<<4 = -16;
    -1<<5 = -32;
    -1<<6 = -64;
    -1<<7 = -128;
    -1<<8 = 0;

    127>>1 = 63;
    127>>2 = 31;
    127>>3 = 15;
    127>>4 = 7;
    127>>5 = 3;
    127>>6 = 1;
    127>>7 = 0;
    127>>8 = 0;

    -128>>1 = -64;
    -128>>2 = -32;
    -128>>3 = -16;
    -128>>4 = -8;
    -128>>5 = -4;
    -128>>6 = -2;
    -128>>7 = -1;
    -128>>8 = -1;

    左移操作(<<)
    规则:
    右边空出的位用0填补
    高位左移溢出则舍弃该高位。
    计算机中常用补码表示数据:
    数据 127,补码和原码一样:0111 1111。
    左移一位: 1111 1110   -> 这个补码对应的原码为:1000 0010  对应十进制:-2
    左移二位: 1111 1100   -> 这个补码对应的原码为:1000 0100  对应十进制:-4
    左移三位: 1111 1000   -> 这个补码对应的原码为:1000 1000  对应十进制:-8
    左移四位: 1111 0000   -> 这个补码对应的原码为:1001 0000  对应十进制:-16
    左移五位: 1110 0000   -> 这个补码对应的原码为:1010 0000  对应十进制:-32
    左移六位: 1100 0000   -> 这个补码对应的原码为:1100 0000  对应十进制:-64
    左移七位: 1000 0000   -> 这个补码对应的原码为:1000 0000  对应十进制:-128
    左移八位: 0000 0000   -> 这个补码对应的原码为:0000 0000  对应十进制:0
    注:
    原码到补码的计算方式:取反+1,
    补码到原码的计算方式:-1再取反。
    数据-1,它的原码为1000 0001,补码为1111 1111
    左移一位: 1111 1110   -> 这个补码对应的原码为:1000 0010  对应十进制:-2
    左移二位: 1111 1100   -> 这个补码对应的原码为:1000 0100  对应十进制:-4
    左移三位: 1111 1000   -> 这个补码对应的原码为:1000 1000  对应十进制:-8
    左移四位: 1111 0000   -> 这个补码对应的原码为:1001 0000  对应十进制:-16
    左移五位: 1110 0000   -> 这个补码对应的原码为:1010 0000  对应十进制:-32
    左移六位: 1100 0000   -> 这个补码对应的原码为:1100 0000  对应十进制:-64
    左移七位: 1000 0000   -> 这个补码对应的原码为:1000 0000  对应十进制:-128
    左移八位: 0000 0000   -> 这个补码对应的原码为:0000 0000  对应十进制:0
    可以看出127和-1的结果完全一样。移位操作与正负数无关,它只是忠实的将所有位进行移动,补0,舍弃操作。
    右移操作(>>)
    规则:

    左边空出的位用0或者1填补。正数用0填补,负数用1填补。注:不同的环境填补方式可能不同;

    低位右移溢出则舍弃该位。

    1、127的补码:0111 1111

    右移一位: 0011 1111   -> 原码同补码一样  对应十进制:63

    右移二位: 0001 1111   -> 原码同补码一样  对应十进制:31

    右移三位: 0000 1111   -> 原码同补码一样  对应十进制:15

    右移四位: 0000 0111   -> 原码同补码一样  对应十进制:7

    右移五位: 0000 0011   -> 原码同补码一样  对应十进制:3

    右移六位: 0000 0001   -> 原码同补码一样  对应十进制:1

    右移七位: 0000 0000   -> 原码同补码一样  对应十进制:0

    右移八位: 0000 0000   -> 原码同补码一样  对应十进制:0

    2、-128的补码:1000 0000

    右移一位: 1100 0000   -> 这个补码对应的原码为:1100 0000  对应十进制:-64

    右移二位: 1110 0000   -> 这个补码对应的原码为:1010 0000  对应十进制:-32

    右移三位: 1111 0000   -> 这个补码对应的原码为:1001 0000  对应十进制:-16

    右移四位: 1111 1000   -> 这个补码对应的原码为:1000 1000  对应十进制:-8

    右移五位: 1111 1100   -> 这个补码对应的原码为:1000 0100  对应十进制:-4

    右移六位: 1111 1110   -> 这个补码对应的原码为:1000 0010  对应十进制:-2

    右移七位: 1111 1111   -> 这个补码对应的原码为:1000 0001  对应十进制:-1

    右移八位: 1111 1111   -> 这个补码对应的原码为:1000 0001  对应十进制:-1

    常见应用
    左移相当于*2,只是要注意边界问题。如char a = 65; a<<1 按照*2来算为130;但有符号char的取值范围-128~127,已经越界,多超出了3个数值,所以从-128算起的第三个数值-126才是a<<1的正确结果。
    而右移相当于除以2,只是要注意移位比较多的时候结果会趋近去一个非常小的数,如上面结果中的-1,0。
    其它的四种位运算:
    与运算(&)
    1、与0相与可清零
    2、与1相与可保留原值
    或运算(|)
    1、与0相或可保留原值
    2、与1相与可齐设1
    异或运算(^)
    1、与0异或保留原值
    2、与1异或比特值反转
    3、可通过某种算法,使用异或实现交换两个值
    异或运算是有结合律的
    取反(~)
  • 相关阅读:
    程序员的健康问题
    比特币解密
    浅谈比特币
    一款能帮助程序员发现问题的软件
    微软为什么总招人黑?
    写了一个bug,最后却变成了feature,要不要修呢?
    不管你信不信,反正我信了
    Excel工作表密码保护的破解
    pip笔记(译)
    super
  • 原文地址:https://www.cnblogs.com/yyangblog/p/1935656.html
Copyright © 2011-2022 走看看