我可以在没有条件的Java中创建1到64位的位掩码吗?

时间:2012-01-23 11:02:32

标签: java bitmask

我想编写一个函数,它接受1到64之间的int,并返回一个适当的“位掩码”,输入数量为1位。

我是这样开始的:

/** Computes a bitmaks */
private static long mask(final int bitsPerValue) {
    return (1L << bitsPerValue) - 1L;
}

但意识到它为64提供了错误的值:

(1L << 64) - 1L == 1L - 1L == 0

现在我有了这个:

/** Computes a bitmaks */
private static long mask(final int bitsPerValue) {
    return (bitsPerValue == 64) ? -1 : ((1L << bitsPerValue) - 1L);
}

这很难看。条件可以改变控制流程,因此它们比简单的算术运算更昂贵。我可以预先计算掩码并将它们放在静态数组中,但是数组访问也比简单的算术操作更昂贵,可能比条件更昂贵。

是否有合理的方式在没有条件的情况下写这个?这段代码每秒会运行数万亿次,所以它必须很快。

3 个答案:

答案 0 :(得分:5)

这是一种没有条件的方法:

private static long mask(final int bitsPerValue) {
    return ((1L << bitsPerValue) - (bitsPerValue >> 6)) - 1L;
}

在Java中1L << bitsPerValue only uses the six lowest-order bits bitsPerValue,这意味着使用bitsPerValue=64调用原始函数与使用bitsPerValue=0调用它相同。我上面提到的版本负责:当bitsPerValue=64时,表达式缩减为

(1L - 1L) - 1L == -1L

现在,如果你真的要称之为“每秒数十亿次”,我认为最好的策略是benchmark代码的所有变体,包括带有条件的变体和带有条件的变体查找表。

答案 1 :(得分:3)

我试过了:

long value = 0xffffffffffffffffl >>> (64 - i); // that's ef ef ef... el.

但这似乎给i = 0带来了问题。我对Java的抱怨没有再次签名无符号。以上工作在c。考虑到'value'是无符号的,上面的内容可能适用于Java 7。

但是,由于你不需要零,上面的方法对你来说很好,即值1到64.

答案 2 :(得分:0)

恕我直言,增加65位值的要求还不够好。我只是使用OR运算来产生价值,它不应该花费很多。像这样:

private static long mask(final int bitsPerValue) {
  long mask = 1;
  long value = 0;
  for (int i=0; i<bitsPerValue; i++ ) {
    value = value | mask;
    mask = mask << 1;
  }
  return value;
}

我看到你不想使用静态数组,但它只是使用64 * 8字节内存的最快方法。此外,我认为很难实现小内存占用和足够好的速度同时。所以,以防万一,最快的方法是:

long valarray[] = new long[64];

private static long[] generateValues() {
  long mask = 1;
  long value = 0;
  for (int i=0; i<64; i++ ) {
    value = value | mask;
    mask = mask << 1;

    valarray[i] = value;
  }
  return valarray;
}

private static long[] mask(final int bitsPerValue) {
  return valarray[bitsPerValue-1];
}

另一种可能的方法是使用BigInteger作为最新的64'1位案例。但我认为这不快,也不丑。