位移操作(左移或右移)是什么?它有什么用途?

67
我看过各种代码中使用的运算符>><<,但我并不理解它们的实际作用和实际用途。如果这些移位操作与x * 2x / 2类似,那么使用*/运算符会有什么区别呢?它们的性能有差异吗?

6
搜索“位移运算”并查看第一个结果(维基百科)可能并不难。它也回答了以上所有问题。 - Jon
1
当然会有性能差异。请参考此链接:http://www.dotnetperls.com/shift - Waqas Shabbir
9
可能是重复的问题,与“什么是位移(bit-shift)运算符,它们如何工作?”相似。 - TylerH
9个回答

53

这里有一个小程序,你可以在其中进行一些位运算,包括位移。

你有一组比特,并且你移动其中的一些比特超出了它们的边界:

1111 1110 << 2
1111 1000

它从右边用新的零填充。 :)

0001 1111 >> 3
0000 0011

从左侧填充。一个特殊情况是前导1。它通常表示负值-具体取决于语言和数据类型。因此,如果要向右移位,则通常希望第一位保持不变。

1100 1100 >> 1
1110 0110

并且这种方法在多次转换中是不变的:

1100 1100 >> 2
1111 0011

如果您不想保留第一位,您可以使用三个相同符号的运算符(在我所知道的Java、Scala、C++、C中,可能还有其它语言也支持):

1100 1100 >>> 1
0110 0110

在其他方向上没有相应的等价物,因为这没有任何意义——也许在你非常特殊的情况下可以,但不是普遍的。

数学上,左移一位是*=2,两次左移是*=4等等。右移一位是/= 2等等。


7
ANSI C 只定义了两个位移运算符 >> 和 <<。 - TML
1
@TML:ANSI C并不是唯一使用位移运算符的语言。C++也使用它们,Java也是,对吧?我猜还有更多的语言。而且我在问题的标题、正文或标签中都没有看到"C"这个字母。 - user unknown
2
不,这个问题并没有;这就是为什么我还给你点了赞。但当时(诚然,这已经快4年前了),我觉得这是一个有价值的评论要添加上去。 :) - TML
它是 2 4 6 8 还是 2 4 8 16 - S.S. Anne
@JL2210:你没有试一下的可能性吗?或者用纸和笔计算一下?因为我写的是*=2,而不是+=2,所以应该是后者,不是吗? - user unknown
我现在明白了。我只是想知道因为我需要将一个指针乘以16。 - S.S. Anne

37

左移位操作可以用来将一个数乘以 2 的任意次方,而 右移 操作可以用来将一个数除以 2 的任意次方。

例如,x = x * 2; 可以写成 x<<1,而 x = x*8 可以写成 x<<3(因为 2 的 3 次方是 8)。同样地,x = x / 2; 可以写成 x>>1 等等。


25

左移操作

x = x * 2^value (正常运算)

x << value (位运算)


x = x * 16 (相当于2^4

左移的等价操作为 x = x << 4

右移操作

x = x / 2^value (正常算术操作)

x >> value (位运算)


x = x / 8 (相当于2^3

右移的等价操作为 x = x >> 3


17

左移:它等于要进行移位的值乘以2的移位的位数次方。

例如:

1 << 3
0000 0001  ---> 1
Shift by 1 bit
0000 0010 ----> 2 which is equal to 1*2^1
Shift By 2 bits
0000 0100 ----> 4 which is equal to 1*2^2
Shift by 3 bits
0000 1000 ----> 8 which is equal to 1*2^3

右移:它等于要进行位移的值除以2的位数次方所得的商。

例如:

8 >> 3
0000 1000  ---> 8 which is equal to 8/2^0
Shift by 1 bit
0000 0100 ----> 4 which is equal to 8/2^1
Shift By 2 bits
0000 0010 ----> 2 which is equal to 8/2^2
Shift by 3 bits
0000 0001 ----> 1 which is equal to 8/2^3

3

比较起除(/)或乘(*)运算符,位移运算符更加高效。

在计算机架构中,除法(/)或乘法(*)需要多个时间单位和寄存器来计算结果。而位移运算符只需要一个寄存器和一个时间单位进行计算。


现代CPU中难道没有一周期乘法吗? - Peter Mortensen

3

左移位运算可用于乘以2的任意次幂。 右移位运算可用于除以2的任意次幂。

x = x << 5; // Left shift
y = y >> 5; // Right shift

在C/C++中,可以这样写:
#include <math.h>

x = x * pow(2, 5);
y = y / pow(2, 5);

2

一些例子:

  • 位运算,例如将数据转换为Base64(它是6位而不是8位)
  • 进行2的幂次方运算(1 << 4等于2^4即16)
  • 在处理位时编写更易读的代码。例如,使用1 << 41 << 5定义常量更易读。

2

我认为在性能方面,您可能会发现按位左移和右移操作可以在大数据集的情况下以o(1)的复杂度执行,从而提高效率。

例如,计算2 ^ n的幂:

int value = 1;
while (exponent<n)
    {
       // Print out current power of 2
        value = value *2; // Equivalent machine level left shift bit wise operation
        exponent++;
         }
    }

使用按位左移操作的类似代码如下:

value = 1 << n;

此外,执行按位操作就像提取用户级数学运算的副本(这是由微控制器和处理器处理的最终机器级指令)。

0

这里是一个例子:

#include"stdio.h"
#include"conio.h"

void main()
{
    int rm, vivek;
    clrscr();
    printf("Enter any numbers\t(E.g., 1, 2, 5");
    scanf("%d", &rm); // rm = 5(0101) << 2 (two step add zero's), so the value is 10100
    printf("This left shift value%d=%d", rm, rm<<4);
    printf("This right shift value%d=%d", rm, rm>>2);
    getch();
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接