views:

186

answers:

5

Hi.

I am trying to make a loop that loops through all different integers where exactly 10 of the last 40 bits are set high, the rest set low. The reason is that I have a map with 40 different values, and I want to sum all different ways ten of these values can be multiplied. (This is just out of curiosity, so it's really the "bitmanip"-loop that is of interest, not the sum as such.)

If I were to do this with e.g. 2 out of 4 bits, it would be easy to set all manually,

0011 = 3,
0101 = 5,
1001 = 9,
0110 = 6,
1010 = 10,
1100 = 12,

but with 10 out of 40 I can't seem to find a method to generate these effectively. I tried, starting with 1023 ( = 1111111111 in binary), finding a good way to manipulate this, but with no success. I've been trying to do this in C++, but it's really the general method(if any) that is of interest. I did some googling, but with little success, if anyone has a good link, that would of course be appreciated too. :)

+6  A: 

You can use any standard implementation of a choose/combination algorithm. Basically you want to choose 10 bits, out of 40, that will be set to 1.

That said, 40 choose 10 is 847,660,528. And that number will be multiplied by however many possible "tail" bits that aren't in the top 40. Presumably the tail bits aren't subject to any rules, so if there are k bits, that would be another 2k factor.

This algorithm, even once you implement it, will be very slow. It may be a good idea to think of a better approach to solve whatever problem you have.

Related questions

polygenelubricants
I figured out that the running time would be quite high, so I won't do it this way, but I kind of got curious about this and wanted to figure it out anyway. And thanks for the link, many good posts there. :)
triktae
+3  A: 

You can simply use next_permutation. Here's a sample to reproduce your 2 out of 4 case (the order varies slightly):

#include <iostream>
#include <algorithm>
using namespace std;
int main () {
 int bits[] = {0,0,1,1};

 do {
  for (int i = 0; i < 4; ++i) cout << bits[i] << " ";
  cout << endl;
 } while ( next_permutation (bits,bits+4) );
 return 0;
}
Frank
This means that every "bit" is really an int, so there are really four ints which are being shuffled around, not four bits inside one int. It's probably as good a solution, but not exactly what I meant.
triktae
doesn't bitset will be better in place of bit[]?
yesraaj
+2  A: 

A bit more complicated, but done purely by bit manipulation. Your example:

#define WIDTH 4
#define BITS 2

void printbits(long pattern) {
  long bit;
  for (bit = 1L << WIDTH - 1; bit; bit >>= 1)
    putchar(pattern & bit ? 49 : 48);
  putchar('\n');
}

void movebits(pattern, bit) {
  long mask = 3L << bit;
  while (((pattern ^= mask) & mask) && (mask < 1L << WIDTH)) {
    mask <<= 1;
    printbits(pattern);
    if (bit)
      movebits(pattern, bit - 1);
  }
}

int main() {
  long pattern = (1L << BITS) - 1L, mask;
  printbits(pattern);
  movebits(pattern, BITS - 1);
}

Your real application:

#define WIDTH 40
#define BITS 10

and, as polygenelubricants says, be prepared to wait for bit :) Of course, you will replace printbits with something more useful to you...

(Edited for insufficient testing :/ Damn typos...)

Amadan
Perfect. Or, at least very close to.(Just had to make even longer ints.) Now I just need to sit down and really understand the condition in the while loop. It actually looks kind of cool, watching those 1s flying leftwards. :D
triktae
Amadan
The other condition (`mask < 1 << WIDTH`) just sets the boundary for the highest 1, since it doesn't have anything to bump into, so I check for mask going past the 4th (or 40th) bit. I hope that helps...
Amadan
Indeed it helps. I would have figured it out by myself(I hope), but seeing an explanation helps speed up the process. So thanks for taking the time.
triktae
A: 

It's easier if you rewrite this as a set of nested loops indicating bit positions:

0011 = 0 1
0101 = 0 2
1001 = 0 3
0110 = 1 2
1010 = 1 3
1100 = 2 3

That is to say, the position P1 of the first bit runs from 0 to 3-1, and the position of the second bit P2 runs repeatedly from P1+1 to 3. Turning this into a generic recursive function is left as an exercise.

MSalters
Thanks. Exercise is always good. And thanks for editing, stupid error on my part.
triktae
+3  A: 

There is a very non-obvious way to do this efficiently: Gosper's method of finding the next higher integer with the same number of 1 bits, from HAKMEM item 175.

lowest_1_bit = prev_combo & -prev_combo;
tmp = prev_combo + lowest_1_bit;
new_combo = (((prev_combo ^ tmp) >> 2) / lowest_1_bit) | tmp;
  • the first line finds the rightmost 1 bit;
  • the second turns the rightmost run of 1 bits to 0, and the 0 just to the left of the run to 1;
  • the third line replaces the 1 bits that were lost by the second line, at the bottom of the word.

Now (assuming you're using a 64-bit integer type) you can start with 1023 and just apply this repeatedly (until the result exceeds 1<<40).

Matthew Slattery
This worked like a charm. I tried reading the HAKMEM paper, but for me at least C++ syntax is easier, so thanks for the nice translation.
triktae