开发者

When are bitwise operations appropriate

I am aware of the basic premise of what bitwise operation are (although would appreciate a "for dummies" explanation); however I am unaware of when it is appropriate to use this technique.

My understanding is that older CPU architectur开发者_开发百科es could perform bitwise operations faster then other operations and hence it was advantageous to know how to use them. Given this is no longer the case; is it still appropriate to perform them and if so, for what purpose and under what conditions? (I am specifically interested in the C# context but am happy to receive general answers)


Bitwise operations are a great way to quickly check for a flag that may be set on a variable.

The following example highlights the benefits of using bitwise operations on a Flag enumeration as well as storing a bitstuffed field into a database. The bitstuffed field can then easily be checked to see if it contains a single value or subset of values from the Flag enumeration.

Example:

A User database table with a tinyint field called Permission. The field is populated using a value created with the enumeration which values are 2^n.

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

Apart from bitwise operations being used to specify values in the enumeration (done at compile time), you can use the enumeration to check if the Permission field in the database contains any subset of the possible values. From the database side you gain the ability to stuff values into a single field - eliminating the need to have a column for each permission and in the code side you gain an easy way to check for a value.

Example bitstuffing (Grant ManageUsers and CreateOrders):

Permission userPermissions = Permission.ManageUsers | Permission.CreateOrders;

Example permission check:

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


The issue is not so much that bitwise operations are faster than integer operation (although they usually are), it's that they are different operations for different purposes.

Conceptually bytes and shorts and ints are really tiny arrays of bits and bitwise operators are boolean array operators. In C# nowadays bitwise operators are mostly used for [Flags] enumerations and in calculations for GetHashCode but there are endless ways that arrays of bits can be used.


You are correct that just because language gives you bitwise operation, you should not use them just because you can. I've seen people use bitwise operators when working with simple booleans and that's not what they are for.

Bitwise operators are useful when working with data structures where pieces of data are not aligned with byte boundary. Generally, this is done when bandwidth (or general memory footprint) is very important. I work on RTP video streaming software and bitwise operations are used both in reading/constructing RTP transmission packets as well as for reading video codec streams, which are often encoded using bits, not bytes.


They can be really useful in embedded control situations when space is at a premium. For example, a single byte of data can represent 8 i/o bits, and masks can be used to retrieve the bits of interest from an i/o port (e.g. if PIN0 = 1, PIN1 = 2, PIN2 = 4, PIN3 = 8 and so on, then:

  • To get the value of PIN0, we can say PORT0 & PIN0 == 0.
  • To set PIN1 to 1, we can cay PORT0 |= PIN1.
  • To set PIN2 to 0, we can say PORT0 &= ~PIN2.

Away from embedded control, I rarely see this approached used these days. In the C# world it's much more common to see individual boolean fields for each value of interest, since the overhead is really not a big deal with modern hardware (though you may run into a case or two where bitwise operations are used to keep many such flags in a single variable).

There is also an interesting application in graphics. A neat trick for cursors or bounding boxes is to add them by XOR'ing the cursor shape with the image below. Performing the same operation again will result in the original image.


One way I find myself using bitwise operators from time to time is to generate subsets of a given string/array using a binary mask, it goes like this: (sorry, c++ code)

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; 
}

You may want to check this insightful contests-oriented programming tutorial: A bit of fun: fun with bits

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜