22

I am reading a program which contains the following function, which is

int f(int n) {
    int c;
    for (c=0;n!=0;++c) 
        n=n&(n-1);
    return c;
}

I don't quite understand what does this function intend to do?

Cam
  • 14,930
  • 16
  • 77
  • 128
user297850
  • 7,705
  • 17
  • 54
  • 76

7 Answers7

39

It counts number of 1's in binary representation of n

Community
  • 1
  • 1
Vladimir
  • 170,431
  • 36
  • 387
  • 313
  • 9
    I like how this wouldn't have needed to be asked if the function had been called `countBinaryOnes` instead of `f`. Also, +1. – Cam Jul 16 '10 at 14:46
  • +1. See 2a here - http://gurmeetsingh.wordpress.com/2008/08/05/fast-bit-counting-routines/ – Dummy00001 Jul 16 '10 at 15:00
  • 2
    Coding elegance: A+. Coding clarity: F. – Jay Jul 16 '10 at 15:29
  • This kind of function not onlyt needs a good name but also a good comment block describing what it does. Even if the name was countBinaryOnes would you trust that is what it did? – Martin York Jul 16 '10 at 16:00
  • @Jay, B+ perhaps. f(INT_MIN) invokes UB. Should be unsigned f(unsigned) IMHO. – Nordic Mainframe Jul 16 '10 at 16:05
  • 1
    Oh, and personally I would have written "n&=n-1" for brevity. On the other hand I probably wouldn't have used a FOR loop, as I avoid having the test refer to a different value from the increment. I find that potentially confusing. – Jay Jul 16 '10 at 21:43
6

The function is INTENDED to return the number of bits in the representation of n. What is missed out in the other answers is, that the function invokes undefined behaviour for arguments n < 0. This is because the function peels the number away one bit a time, starting from the lowest bit to the highest. For a negative number this means, that the last value of n before the loop terminates (for 32-bit integers in 2-complement) is 0x8000000. This number is INT_MIN and it is now used in the loop for the last time:

n = n&(n-1)

Unfortunately, INT_MIN-1 is a overflow and overflows invoke undefined behavior. A conforming implementation is not required to "wrap around" integers, it may for example issue an overflow trap instead or leave all kinds of weird results.

Nordic Mainframe
  • 28,058
  • 10
  • 66
  • 83
  • 1
    Counting set bits in a signed quantity is generally not what you want to do anyway. The function should just accept `unsigned int`. – Karl Knechtel Aug 27 '11 at 23:48
5

It is a (now obsolete) workaround for the lack of the POPCNT instruction in non-military cpu's.

mvds
  • 45,755
  • 8
  • 102
  • 111
4

This counts the number of iterations it takes to reduce n to 0 by using a binary and.

John Weldon
  • 39,849
  • 11
  • 94
  • 127
3

The expression n = n & (n - 1) is a bitwise operation which replaces the rightmost bit '1' to '0' in n.

For examle, take an integer 5 (0101). Then n & (n - 1)(0101) & (0100)0100 (removes first '1' bit from right side).

So the above code returns the number of 1's in binary form of given integer.

Al.G.
  • 4,327
  • 6
  • 31
  • 56
sai Charan
  • 31
  • 1
1

It shows a way how not to program(for the x86 Instruction set), using a intrinsic/inline assembler instruction is faster and better to read for something simple like this. (but this is only true for a x86 Architecture as far as i know, i don't know how's it about ARM or SPARC or something else)

Quonux
  • 2,975
  • 1
  • 24
  • 32
0

Could it be it tries to return the number of significant bits in n? (Haven't thought through it completely...)

TheBlastOne
  • 4,291
  • 3
  • 38
  • 72