1

I have defined the following:

typdef enum {
  none = 0,
  alpha = 1,
  beta = 2,
  delta = 4
  gamma = 8
  omega = 16,
} Greek;

Greek t = beta | delta | gammax

I would like to be able to pick one of the flags set in t randomly. The value of t can vary (it could be, anything from the enum).

One thought I had was something like this:

r = 0;
while ( !t & ( 2 << r ) { r = rand(0,4); }

Anyone got any more elegant ideas?

If it helps, I want to do this in ObjC...

Nick
  • 2,803
  • 1
  • 39
  • 59
  • What's your idea of "more elegant" in this case? I can think of a solution that only generates one random number but it requires a few more lines of code to work. – rmaddy Nov 05 '14 at 23:58
  • Also, depending on how "random" you want to be, you can find the lowest or highest set bit with a compiler builtin: [Finding position of 1s efficiently in an bit array](http://stackoverflow.com/q/9295938). – jscs Nov 06 '14 at 00:07
  • @rmaddy By more elegant, I mean not needing a while loop. My example is a bit "fire at the wall and see what sticks".. If `t = delta` and we're picking from that random "set" (of 1) then there is a 5 in 6 chance the random will miss every time until it picks the "active" one from the set. @JoshCaswell does that just pick the highest/lowest set bit? – Nick Nov 06 '14 at 09:16

1 Answers1

1

Assuming I've correctly understood your intent, if your definition of "elegant" includes table lookups the following should do the trick pretty efficiently. I've written enough to show how it works, but didn't fill out the entire table. Also, for Objective-C I recommend arc4random over using rand.

First, construct an array whose indices are the possible t values and whose elements are arrays of t's underlying Greek values. I ignored none, but that's a trivial addition to make if you want it. I also found it easiest to specify the lengths of the subarrays. Alternatively, you could do this with NSArrays and have them self-report their lengths:

int myArray[8][4] = {
    {0},
    {1},
    {2},
    {1,2},
    {4},
    {4,1},
    {4,2},
    {4,2,1}
};
int length[] = {1,1,1,2,1,2,2,3};

Then, for any given t you can randomly select one of its elements using:

int r = myArray[t][arc4random_uniform(length[t])];

Once you get past the setup, the actual random selection is efficient, with no acceptance/rejection looping involved.

pjs
  • 18,696
  • 4
  • 27
  • 56