我想编写一个函数,它接受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);
}
这很难看。条件可以改变控制流程,因此它们比简单的算术运算更昂贵。我可以预先计算掩码并将它们放在静态数组中,但是数组访问也比简单的算术操作更昂贵,可能比条件更昂贵。
是否有合理的方式在没有条件的情况下写这个?这段代码每秒会运行数万亿次,所以它必须很快。
答案 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位案例。但我认为这不快,也不丑。