views:

147

answers:

3

Given a 64 bit integer, where the last 52 bits to be evaluated and the leading 12 bits are to be ignored, what is the fastest way to loop every single combination of 7 bits on and all other bits off?

Example:

First permutation:

0[x57]1111111

Last permutation

00000000000011111110[x45]

Where 0[xn] means n off (zero) bits.

Speed is absolutely crucial, we are looking to save every clock cycle we can as it is part of a greater solution that needs to evaluate billions of states in a reasonable amount of time.

A working solution is not required, but some pseudo code would do just fine :)

+4  A: 

What you need is a good algorithm that will take you from one permutation to the next in minimal time.

Now, the first algorithm that comes to mind is to go through all combinations with seven loops.

  • The first loop goes through the 52 bits, setting one for the next loop.
  • The second loop goes through the bits after the set one, setting one for the third loop.
  • ...ect

This will give you the fastest iteration. Here is some pseudo C++ code:

__int64 deck;
int bit1, bit2, bit3, ...;
for (bit1=0;bit1<52-6;bit1++) {
  for (bit2=bit1+1;bit2<52-5;bit2++) {
    ...
      for (bit7=bit6+1;bit7<52;bit7++) {
        deck = (1<<bit1)+(1<<bit2)+(1<<bit3)+...;  // this could be optimized.
        // do whatever with deck
      }
    ...
  }
}

// note: the 52-6, 52-5, will be pre-calculated by the compiler and are there for convenience. You don't have to worry about optimizing this.

There is your solution right there. If you want to check that it works, I always downscale it. For example, following that algorithm on a 4bit number where you need to set 2 bits would go like this:

1100
1010
1001
0110
0101
0011
Alexander Rafferty
Just as a note: This algorithm operates on the first 52 bits, not the last. A simple fix would be to adjust the bit shift operations.
Alexander Rafferty
Excellent answer, thank you. I do think there are more solutions though, I'm writing an answer that is going to be wrong but might give you an idea of a different way of solving this
Tom Gullen
Never mind my answer will be too vague, ill write it in the question comments
Tom Gullen
I've written a comment to my question, if my comment is plausible, would it probably outperform 7 nested loops?
Tom Gullen
That's the way I would have done it. The inner loop could be unrolled and the "outer" bits ORed outside it. Also, the moving of the inner bit could be done with a 1-shift.
Mike Dunlavey
@Tom: With nested loops, and the inner loop unrolled, the inner loop looks something like this: `eval(outerbits|1);eval(outerbits|2;eval(outerbits|4);...`. Seems hard to beat.
Mike Dunlavey
+8  A: 

I think you'll be interested in this article: http://realtimecollisiondetection.net/blog/?p=78

It solves your problem in very efficient way.

ruslik
At a quick glance I thought: "Collision detection? WTF?"
Alexander Rafferty
+1. Every time I trip over that blog, I think "I should be reading this more often." Then I forget about it until I trip over it again. I *really* should be reading it more often ;-) Back on topic, that is a really interesting approach to the problem.
RBerteig
Hmm.. seven operations per iteration. It would be far more efficient.
Alexander Rafferty
Thank you, excellent article, will read it fully, just as a question, would this perform as fast as, or if not faster than the solution possibility I have outlined in the question comments?
Tom Gullen
@Tom I really don't think that something could outperform it.
ruslik
Great article. So if I declare my int64 = 127, then perform these seven operations 1000 times I will have my firs 1000 permutations?
Tom Gullen
@Tom Right. Also, you can change anytime the number of required bits just by changing the initial value: `(1 << N) - 1`
ruslik
Excellent, thanks again! And am I right in saying that there are 133,784,560 combinations for my arrangement of 7 bits within 52 (52 choose 7)? So I know when to stop the shifting I keep track of total # of permutations.
Tom Gullen
And is there an easy way to return the permutation number based on an input? IE getPerm(127) = 1, getPerm(4468415255281664) = 133,784,560 or should I probably create another question for that?
Tom Gullen
@Tom `while (!(perm >> 52))` is safer.
ruslik
+1  A: 

I think there is a relationship between each permutation.

alt text

We can see the number increases with permutation # with a pattern.

This maths isn't correct for all solutions, but works for some, hopefully indicating what I mean:

Permutation 3 difference = ((3%7+1)^2) * (roundUp(3/7) = 16
Permutation 10 difference = ((10%7+1)^2) * (roundUp(10/7) = 32

So we would loop from the absolute values:

int perm = 1;
for int64 i = 127; perm < totalPermutations
{
    i = i + ((perm%7+1)^2) * (roundUp(perm/7);
    perm++;
}

Again the maths is wrong, but gives an idea, I am sure it is possible to come up with a formula for this. As to whether it outperforms bitwise operations would have to be tested.

Tom Gullen
Interesting solution, but is it better performance wise?
Alexander Rafferty
My maths is horrific, and I haven't managed to calculate a working formula so I don't know yet :) Will post it here if I can find it
Tom Gullen