0

Given the size of a mask of size size I'd like to create a long mask with the bottom size bits of the mask set, and the upper bits zero. For example example, the mask for size == 4 is 0b1111 (aka 0x0000000000000000F), and so on. size must be in the range 0 <= size <= 64.

A typical attempt that isn't correct for all inputs is as follows:

long makeMask(int size) {
  return (1L << size) - 1;
}

... but this fails for size == 64, returning 0 rather than the expected all-ones: 0xFFFFFF..... For int masks, I could cast to long to avoid this issue, but for long I don't see a similar workaround.

I could do something like:

long makeMask(int size) {
  return size == 64 ? -1L : (1L << size) - 1;
}

... but I'd really like to avoid an unpredictable branch in there.

BeeOnRope
  • 60,350
  • 16
  • 207
  • 386
  • 1
    Maybe you can try to convert this [C++ answer](http://stackoverflow.com/a/28703383/5517612) to Java? – Todd Sewell Nov 23 '16 at 22:58
  • 1
    There will always be a boundary problem. Choose between yours at 64 and @LukeLee's at zero. Or make a lookup table. – user207421 Nov 23 '16 at 23:46
  • @ToddSewell - right, but both solutions boil down to a conditional like what I have above (or conditional move like reductions of the conditional, e.g., `-(size != 0) & ...`. – BeeOnRope Nov 23 '16 at 23:49
  • @EJP - of course there will not _always be a boundary_ problem - the conditional above has no boundary problem. If you mean it can't be efficiently & correctly implemented without a lookup table - well I guess that remains to be seen. My experience is that often it is *is* possible with an extra instruction or two. – BeeOnRope Nov 23 '16 at 23:50
  • There will always be a boundary problem with a purely bit-shifting implementation that you have to solve with a conditional branch or a lookup table. I haven't said a word about efficiency, or about a lookup table being the only other possibility: don't put words into my mouth. You need to make up your mind as to whether or not you need to avoid the branch. You've now claimed both. – user207421 Nov 23 '16 at 23:57
  • The shift-based implementation I showed first was simply to shortcircuit all the answers that would immediately pop up saying "hey, you can do it like `(1L << size) - 1` !!", and then I have to comment that it doesn't work, etc. I don't presuppose any implementation! I don't necessarily need to avoid a branch, but _in practice_ the branch produces slow code when the branch in unpredictable. I think my question is clear, but maybe you should make your claim clearer? Is it that the conditional solution I gave above is already _optimal_? Is it that _no_ correct, branch-free solutions even exist? – BeeOnRope Nov 24 '16 at 00:02
  • @EJP - I clarified the first "solution" to make it clearer that it's simply demonstrating a non-solution to avoid many incorrect redundant answers. – BeeOnRope Nov 24 '16 at 00:03
  • I have no idea what you're talking about. I have not said one word about efficiency, optimality, ... But I *have* suggested an alternative implementation that you are busily ignoring while busily trying to argue with me. I don't know what the argument is about. I am actually agreeing with you that a pure bit-shift cannot work. – user207421 Nov 24 '16 at 00:04
  • I'm trying to understand your claim that: _there will always be a boundary problem._ You should be more clear about what you mean. Clearly there are many solutions that suffer from no boundary problem (including your example of a LUT or solutions that loop 64 times, or solutions that fix the boundary problem with various methods). – BeeOnRope Nov 24 '16 at 00:08
  • I have *already* clarified it, in my second comment. – user207421 Nov 24 '16 at 00:15
  • It isn't clear to me, but let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/128886/discussion-between-beeonrope-and-ejp). – BeeOnRope Nov 24 '16 at 00:16

1 Answers1

3

You can use the inverse of the 7th bit and shift that:

long x = (size >> 6) ^ 1;
return (x << size) - 1;

When size = 64 this sets x = 0 and (0 << whatever) - 1 is obviously -1.

In other cases it simplifies to the old (1L << size) - 1.

harold
  • 61,398
  • 6
  • 86
  • 164