tags:

views:

65

answers:

3

I have a large bitset that I want to frequently reset individual bits in it. Which method is faster?

a) bitset[word_index] ^= 1 << bit_index

or

b) bitset[word_index] &= ~(1 << bit_index)

The application is for the desktop (if that plays a role).

+4  A: 

They don't do the same thing.

Option a will flip the given bit; option b will clear it. Go with whichever actually reflects your intention. If you want to clear the bit but you happen to know it will always be set, I'd use option b as it states the "clear the bit" part more obviously.

When you say you want to do this "frequently" - just how frequently is this? Do you have any evidence to suggest that this is the bottleneck in your application? If not, why are you interested in the fastest way of doing it rather than the most readable way?

Jon Skeet
Yes, I know the difference; a bit will be set before the operation, so both are equal in this context.When I say 'frequent' I mean lots of times per 100 seconds.
axilmar
+1  A: 

Assuming your code correctly does what you intend it to: this is termed a micro-optimisation.

There is unlikely to be any substantial difference. A good optimising compiler will produce fast code either way.

Suggest you benchmark in your particular circumstances. (Also, suggest you write unit tests)

Mitch Wheat
+2  A: 

if you want to CLEAR a bit at position N you have to set up a mask with a 0 in position N and 1s everywhere else then use the bitwise AND operator like this:

a &= ~(1 << N);

if you want to SET a bit at position N you have to set up a mask with a 1 in position N and 0s everywhere else then use the bitwise OR operator like this:

a |= (1 << N);

if you want to TOGGLE a bit at position N you have to set up a mask with a 1 in position N and 0s everywhere else then use the bitwise XOR operator like this:

a ^= (1 << N);

you can apply the same reasoning to affect multiple bits at once, typically by ORing togethre individual bit-masks. For example to clear the 3rd, 5th, and 9th bits in a you might do:

a &= ~( (1 << 3) | (1 << 5) | (1 << 9) );

why would you do it like that instead of just saying:

a &= 0x0DD7;

two reasons -

(1) typically the 3, 5, and 9 won't be literals, but defined constants for better readability. (2) the compiler will turn it into that at compile time anyway (given that you use constants), no need to make your code less readable.

vicatcu
Thank you, but which one is faster on modern CPUs? the AND/NOT combination is two instructions, the XOR is one instruction. Does it play a role in modern CPUs?
axilmar
@axilmar, AND/NOT is not a unified instruction in any instruction set architecture I am familiar with, whereas XOR typically is, so yes if you have a situation that can equivalently be accomodated with one or the other, then by all means use the XOR form. Realize, however, that the two lines of code in your question are in fact doing fundamentally different operations (as other answer-ers have noted).
vicatcu