何时按位运算是合适的

时间:2011-04-23 03:34:15

标签: c# algorithm bit-manipulation bit-shift

我知道按位操作的基本前提是什么(虽然会欣赏“for dummies”的解释);但是我不知道何时使用这种技术是合适的。

我的理解是older CPU architectures could perform bitwise operations faster then other operations因此知道如何使用它们是有利的。鉴于此情况已不再适用;是否仍然适合执行它们,如果是,它的目的和条件是什么? (我特别感兴趣的是C#语境,但很高兴收到一般答案)

5 个答案:

答案 0 :(得分:6)

按位运算是快速检查可能在变量上设置的标志的好方法。

以下示例强调了对Flag枚举使用按位运算以及将bitstuffed字段存储到数据库中的好处。然后可以轻松检查bitstuffed字段,以查看它是否包含Flag枚举中的单个值或值子集。

示例:

User数据库表,其tinyint字段名为Permission。使用通过枚举创建的值填充该字段,其值为2 ^ n。

[Flags]
public enum Permission : byte
{
    None = 0,
    ManageUsers = 1 << 0,
    CreateOrders = 1 << 1,
    PurchaseEquipment = 1 << 2,
    CancelOrders = 1 << 3,
}

除了用于指定枚举中的值的按位运算(在编译时完成)之外,您还可以使用枚举来检查数据库中的Permission字段是否包含可能值的任何子集。从数据库方面,您可以将值填充到单个字段中 - 无需为每个权限添加列,并且在代码方面,您可以轻松地检查值。

示例位填充(Grant ManageUsers和CreateOrders):

Permission userPermissions = Permission.ManageUsers | Permission.CreateOrders;

示例权限检查:

public bool HasPermissions(Permission userPermissions, Permission permissionsToCheckFor)
{
    return permissionsToCheckFor == Permission.None ? 
        false : 
        (userPermissions & permissionsToCheckFor) == permissionsToCheckFor;
}

答案 1 :(得分:5)

问题不在于按位操作比整数操作更快(尽管它们通常是这样),而是不同操作不同目的。

从概念上讲,字节,短路和整数实际上是比特的数组,而按位运算符是布尔数组运算符。在C#中,现在按位运算符主要用于[Flags]枚举和GetHashCode的计算,但是有无数种方法可以使用位数组。

答案 2 :(得分:4)

你是对的,因为语言给你按位操作,你不应该只是因为你可以使用它们。我看到人们在使用简单的布尔值时使用按位运算符,而这不是它们的用途。

按位运算符在处理数据结构时非常有用,在数据结构中,数据块与字节边界不对齐。通常,这是在带宽(或通用内存占用量)非常重要时完成的。我致力于RTP视频流软件,并且按位操作用于读取/构建RTP传输数据包以及读取视频编解码器流,这些数据流通常使用位而不是字节进行编码。

答案 3 :(得分:2)

当空间非常宝贵时,它们在嵌入式控制环境中非常有用。例如,单个字节的数据可以表示8个i / o位,并且掩码可用于从i / o端口检索感兴趣的位(例如,如果PIN0 = 1, PIN1 = 2, PIN2 = 4, PIN3 = 8等等,则:

  • 要获得PIN0的值,我们可以说PORT0 & PIN0 == 0
  • 要将PIN1设置为1,我们可以发送PORT0 |= PIN1
  • 要将PIN2设置为0,我们可以说PORT0 &= ~PIN2

远离嵌入式控制,我很少看到这些日子使用过。在C#世界中,为每个感兴趣的值看到单独的布尔字段更为常见,因为开销对于现代硬件来说真的不是很大(尽管你可能遇到一个或两个案例,其中使用按位运算来保持许多这样的单个变量中的标志。)

图形中也有一个有趣的应用。游标或边界框的一个巧妙技巧是通过将光标形状与下面的图像进行异或来添加它们。再次执行相同的操作将产生原始图像。

答案 4 :(得分:2)

我发现自己不时使用按位运算符的一种方法是使用二进制掩码生成给定字符串/数组的子集,它是这样的:(抱歉,c ++代码)

string s = "abcde";
for(int i = 0; i < 1<<s.size(); i++) {
  string tmp;
  for(int j = 0; j < s.size(); j++) if(i & 1<<j) tmp.push_back(s[j]);
  cout<<tmp<<endl; 
}

您可能想要查看这个富有洞察力的面向竞赛的编程教程:A bit of fun: fun with bits