4

OK, what I want is pretty straight forward :

  • Set Nth bit of a number (= make it '1')
  • Unset Nth bit of a number (= make it '0')

This is my code so far (in the form of 2 macros) :

#define SETBIT(X,Y)     X|=(1ULL<<(Y))
#define UNSETBIT(X,Y)   X&=(~(1ULL<<(Y)))

They are both working fine. The thing is :

  • Is there anything that could be optimized?
  • Could it be made even faster?

(Both operations are supposed to be performed some millions of times per second, so performance is more than crucial).

Dr.Kameleon
  • 22,532
  • 20
  • 115
  • 223
  • 1
    No. And No. These are as fast as you get. – Daniel Fischer Dec 30 '12 at 16:04
  • 1
    there is always the inline assembly if you know the asm for your machine and if your compiler supports this feature ... – user1824407 Dec 30 '12 at 16:06
  • 1
    have u tried `bitset` class... – Anirudha Dec 30 '12 at 16:06
  • 1
    @user1824407 I doubt that'd be faster. C++ is a compiled language, I doubt you could, for this simple case, produce faster assembler code than the compiler. – Luchian Grigore Dec 30 '12 at 16:07
  • @LuchianGrigore mmm, it depends, with inline assembly you can create a small function, that will probably not gain that much but you will get the exact same behaviour with any compiler, it will be more consistent and less compiler-dependent. – user1824407 Dec 30 '12 at 16:09
  • @user1824407 can you cook up an example? – Luchian Grigore Dec 30 '12 at 16:10
  • 1
    @LuchianGrigore about what ? if you mean manipulating the bits with asm instrunctions there is already an answer that reflect this idea http://stackoverflow.com/a/14092240/1824407 , if you mean something else simply use AT&T or Intel asm inline assembly, many compiler support this feature with some exception like the cheap Visual Studio where there is no asm at all for the 64 bit C++ compiler . – user1824407 Dec 30 '12 at 16:15
  • @user1824407 those aren't standard, so I don't see how you can "get the exact same behaviour with any compiler, it will be more consistent and less compiler-dependent". – Luchian Grigore Dec 30 '12 at 17:38

4 Answers4

6

You can marginally speed up compilation time by getting rid of the macros, but that's about it. Bit twiddling is fast enough so it shouldn't be an issue.

This is the idiomatic way of doing it, I wouldn't change a thing.

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
  • Why would getting rid of macros speed up compilation, especially assuming they are in a .h file which exists anyway? Preprosessing step is a must anyway, and macro substitution is basically simple string replacement, so it should be totally irrelevant for compilation time. – hyde Dec 30 '12 at 17:01
  • @hyde macro substitution happens in pre-processing, which is part of the whole compilation process. How can it be irrelevant? – Luchian Grigore Dec 30 '12 at 17:18
  • I mean, if having these macros increases compilation time by a millisecond or whatever... Would you call that relevant? – hyde Dec 30 '12 at 17:30
  • 3
    Well, to me "marginal" means roughly "relevant in marginal cases" or "barely noticable", and I don't agree this makes even marginal difference in compilation time. But, comments are not for debate, so lets leave it at this. – hyde Dec 30 '12 at 17:46
3

This is the standard way of setting and clearing a bit in C.

If you want to potentially speed up these macros you can have a look at Linux assembly implementations of these operations.

For example, for x86:

http://lxr.linux.no/linux/arch/x86/include/asm/bitops.h

Look for __clear_bit and __set_bit inline functions.

ouah
  • 142,963
  • 15
  • 272
  • 331
  • Actually, if he doesn't need atomicity and non-reordering guarantees, he should probably look at `__set_bit` and `__clear_bit` instead. – Matteo Italia Dec 30 '12 at 16:13
  • Actually, the OP should look at the compiler generated assembly code, regardless of Windows, Linux or the processor. – Thomas Matthews Dec 30 '12 at 23:45
2

Those macros are optimal and idiomatic, so the compiler will probably recognize those expressions if there are optimizations to do.

The only speedup you may obtain is... avoiding their usage if there are better alternatives. If you are doing often the same multi-bit operation (say, turn on bit 0, 2, and 4) you may gain something by performing all these operations with e.g. a single or instead of using multiple SETBITs.

Matteo Italia
  • 123,740
  • 17
  • 206
  • 299
2

First of all, you should fix the macros to be like this:

#define SETBIT(X,Y)     ( (X) |= 1ULL << (Y) )
#define UNSETBIT(X,Y)   ( (X) &= ~(1ULL << (Y)) ) )

That way code like SETBIT(a, 2) + 1; would work more like expected and SETBIT(1+a, 2); would produce error as expected.

You will probably never use the macros that way, but extra parenthesis are free anyway, and solving macro-related issues can be such a PITA, that always put the extra () or {} around macros.

ADDITION: With inline assembly and CPU with bit rotation operation, and assuming Y is not known at compile time, UNSETBIT can be made faster, avoiding a NOT... Pseudocode:

X = X OR (0xFFFFFFFFFFFFFFFE ROL Y)

Then while those macros are as efficient as it gets (C compiler should optimize them to ideal assembly instructions), you should perhaps provide macros to manipulate several bits, like:

#define SET2BITS(X, B1, B2)     ( (X) |= 1ULL << (B1) | 1ULL << (B2) )

Also a function-like macro for using inside expressions might be more efficient in some situations (though compiler optimizations will probably achieve same end result anyway):

#define BITSETVAL(X, B)     ( (X) | 1ULL << (B) )
hyde
  • 60,639
  • 21
  • 115
  • 176