16

What is the meaning of (number) & (-number)? I have searched it but was unable to find the meaning

I want to use i & (-i) in for loop like:

for (i = 0; i <= n; i += i & (-i))
MD XF
  • 7,860
  • 7
  • 40
  • 71
Aseem Goyal
  • 2,683
  • 3
  • 31
  • 48
  • 1
    A bitwise and with the negation. – Basile Starynkevitch Oct 10 '12 at 12:08
  • 28
    Why do you want to use it, if you do not know what it means? – Rowland Shaw Oct 10 '12 at 12:09
  • 10
    You want to use it in a loop but you don't know what it does? – Mike Oct 10 '12 at 12:09
  • 2
    I hope that `i` is declared with an unsigned type. – CB Bailey Oct 10 '12 at 12:10
  • i was solving a question but was unable to do it. i had a look at solution and this was the only thing i couldnot understand.my approach was a timeout so i think it is used to optmize code – Aseem Goyal Oct 10 '12 at 12:13
  • 3
    The `i=0` initialiser does make the loop infinite since `i&(-i)` is also 0. What's does the content of the loop do? – Skizz Oct 10 '12 at 12:22
  • @SKIZZ: I dont think 'i&(-i)' is aalways 0. With twos-compliment, 1&-1 results in 1. – Mooing Duck Oct 10 '12 at 14:25
  • 3
    @MooingDuck: When `i=0` as it is in the code that is given, `i&(-i)` is also 0 and so the loop is infinite provided the body does not change `i`. You're right that `i&(-i) != 0` for `i > 0`, but `i` is zero in the question. – Skizz Oct 10 '12 at 14:49
  • With `i = 0;`, this is an infinite loop as others commented. Let's assume that's **NOT** the intention. Let's try `for (i = 1; i <= n; i += i & -i) ;`. First iteration, i is 1, -i is -1, i&-i is 0x01 & 0xff is 1 (assume signed byte) so i += i&-i gives i is 2. Second iteration, i is 2, -i is -2, i & -i is 0x02 & 0xfe is 2, so i += i & -i gives i is 4 ('is' means 'equals'). Then 8,16,32,... till i > n. OP says 'solving a question' so might be some CompSci exam testing binary logic and arithmetic. Maybe the `i=0` was correct and this was a find the bug exam. Still need binary skills to prove it. – Uber Kluger Sep 25 '20 at 08:37

4 Answers4

31

Assuming 2's complement (or that i is unsigned), -i is equal to ~i+1.

i & (~i + 1) is a trick to extract the lowest set bit of i.

It works because what +1 actually does is to set the lowest clear bit, and clear all bits lower than that. So the only bit that is set in both i and ~i+1 is the lowest set bit from i (that is, the lowest clear bit in ~i). The bits lower than that are clear in ~i+1, and the bits higher than that are non-equal between i and ~i.

Using it in a loop seems odd unless the loop body modifies i, because i = i & (-i) is an idempotent operation: doing it twice gives the same result again.

[Edit: in a comment elsewhere you point out that the code is actually i += i & (-i). So what that does for non-zero i is to clear the lowest group of set bits of i, and set the next clear bit above that, for example 101100 -> 110000. For i with no clear bit higher than the lowest set bit (including i = 0), it sets i to 0. So if it weren't for the fact that i starts at 0, each loop would increase i by at least twice as much as the previous loop, sometimes more, until eventually it exceeds n and breaks or goes to 0 and loops forever.

It would normally be inexcusable to write code like this without a comment, but depending on the domain of the problem maybe this is an "obvious" sequence of values to loop over.]

Steve Jessop
  • 273,490
  • 39
  • 460
  • 699
  • it seems that he is going to change the value of i in the loops body..i think `i=i&(-i)` is for keeping it `positive` – Anirudha Oct 10 '12 at 12:31
  • @Anirudha: if it is intended to keep it positive then it doesn't work for the case where only the topmost bit is set. But anyway, the questioner says in a comment that `i` is unsigned. – Steve Jessop Oct 10 '12 at 12:32
5

Assuming that negative values are using two's complement. Then -number can be calculated as (~number)+1, flip the bits and add 1.

For example if number = 92. Then this is what it would look like in binary:

number               0000 0000 0000 0000 0000 0000 0101 1100
~number              1111 1111 1111 1111 1111 1111 1010 0011
(~number) + 1        1111 1111 1111 1111 1111 1111 1010 0100
-number              1111 1111 1111 1111 1111 1111 1010 0100
(number) & (-number) 0000 0000 0000 0000 0000 0000 0000 0100

You can see from the example above that (number) & (-number) gives you the least bit.

You can see the code run online on IDE One: http://ideone.com/WzpxSD

Here is some C code:

#include <iostream>
#include <bitset>
#include <stdio.h>
using namespace std;

void printIntBits(int num);
void printExpression(char *text, int value);

int main() {
  int number = 92;

  printExpression("number", number);
  printExpression("~number", ~number);
  printExpression("(~number) + 1", (~number) + 1);
  printExpression("-number", -number);
  printExpression("(number) & (-number)", (number) & (-number));

  return 0;
}

void printExpression(char *text, int value) {
  printf("%-20s", text);
  printIntBits(value);
  printf("\n");
}

void printIntBits(int num) {
    for(int i = 0; i < 8; i++) {
        int mask = (0xF0000000 >> (i * 4));
        int portion = (num & mask) >> ((7 - i) * 4);
      cout << " " << std::bitset<4>(portion);
    }
}

Also here is a version in C# .NET: https://dotnetfiddle.net/ai7Eq6

Luis Perez
  • 27,650
  • 10
  • 79
  • 80
4

I thought I'd just take a moment to show how this works. This code gives you the lowest set bit's value:

int i = 0xFFFFFFFF; //Last byte is 1111(base 2), -1(base 10)
int j = -i;         //-(-1) == 1
int k = i&j;        //   1111(2) = -1(10) 
                    // & 0001(2) =  1(10)
                    // ------------------
                    //   0001(2) = 1(10). So the lowest set bit here is the 1's bit


int i = 0x80;       //Last 2 bytes are 1000 0000(base 2), 128(base 10)
int j = -i;         //-(128) == -128
int k = i&j;        //   ...0000 0000 1000 0000(2) =  128(10) 
                    // & ...1111 1111 1000 0000(2) = -128(10)
                    // ---------------------------
                    //   1000 0000(2) = 128(10). So the lowest set bit here is the 128's bit

int i = 0xFFFFFFC0; //Last 2 bytes are 1100 0000(base 2), -64(base 10)
int j = -i;         //-(-64) == 64
int k = i&j;        //   1100 0000(2) = -64(10) 
                    // & 0100 0000(2) =  64(10)
                    // ------------------
                    //   0100 0000(2) = 64(10). So the lowest set bit here is the 64's bit

It works the same for unsigned values, the result is always the lowest set bit's value.

Given your loop:

for(i=0;i<=n;i=i&(-i))  

There are no bits set (i=0) so you're going to get back a 0 for the increment step of this operation. So this loop will go on forever unless n=0 or i is modified.

Mike
  • 47,263
  • 29
  • 113
  • 177
  • it is i += i & (-i);somebody edited my post and did i = i & (-i); – Aseem Goyal Oct 10 '12 at 13:10
  • @aseem - OK, but it doesn't matter unless `i` is changed inside the loop(which is probably why it was edited). `i=0`, therefore `i&(-i)=0`, so `i+=i&(-i)` is just going to add 0 in so `i=0+0&(-0)` and it stays 0. – Mike Oct 10 '12 at 13:23
2

The operation i & -i is used for isolating the least significant non-zero bit of the corresponding integer.

  • In binary notation num can be represented as a1b, where a represents binary digits before the last bit and b represents zeroes after the last bit.

  • -num is equal to (a1b)¯ + 1 = a¯0b¯ + 1. b consists of all zeroes, so consists of all ones.

    • -num = (a1b)¯ + 1 => a¯0b¯ + 1 => a¯0(0…0)¯ + 1 => ¯0(1…1) + 1 => a¯1(0…0) => a¯1b
  • Now, num & -num => a1b & a¯1b => (0..0)1(0..0)

For e.g. if i = 5

| iteration | i | last bit position | i & -i|
|-------- |--------|-------- |-----|
| 1    | 5 = 101     | 0 | 1 (2^0)|
| 2    | 6 = 110     | 1 | 2 (2^1)|
| 3    | 8 = 1000    | 3 | 8 (2^3)|
| 4    | 16 = 10000  | 4 | 16 (2^4)|
| 5    | 32 = 100000 | 5 | 32 (2^5)| 

This operation in mainly used in Binary Indexed Trees to move up and down the tree

PS: For some reason stackoverflow is treating table as code :(