一个字节的尾随/前导零计数

时间:2008-12-18 03:33:57

标签: chess bitcount

我正在使用Java而我正在编写国际象棋引擎。

我正在尝试查找前1位的索引和一个字节中最后1位的索引。

我目前在Java中使用Long.numberOfTrailingZeros()(或类似的东西),并希望模拟该功能,除了字节。

会是这样的:

byte b = 0b011000101;
int firstOneBit = bitCount ((b & -b) - 1);

如果是这样,我将如何相对有效地实现bitCount。我不介意好解释,请不要只给我代码。

4 个答案:

答案 0 :(得分:3)

使用包含256个条目的查找表。 创建它:

unsigned int bitcount ( unsigned int i ) {
unsigned int r = 0;
while ( i ) { r+=i&1; i>>=1; } /* bit shift is >>> in java afair */
return r; 
}

这当然不需要很快,因为你最多执行256次来启动你的表格。

答案 1 :(得分:2)

正确的答案是,大多数处理器都有一些特殊的指令来执行此类操作(前导零,尾随零,数量等)。 x86有bsf / bsr,powerpc有clz,依此类推。希望Integer.numberOfTrailingZeros足够智能使用它们,但这可能是有机会在Java中使用这种特定于平台的函数的唯一方法(如果它甚至使用它们)。

Aggregate Magic Algorithms是另一个有这种问题的方法,从明显的(查找表)到一些相当聪明的SWAR方法。但我怀疑如果java运行时对后者很聪明,它们都会输给Integer(x).numberOfTrailingZeros();它应该可以优化拳击并使用特定于平台的技术为numberOfTrailingZeros,如果它同时做到两个都会赢。

仅仅为了完整性,另一个经典的点击打击存档是旧的MIT HAKMEM集合(如果你的PDP-6/10汇编技能已经生锈,那么还有一个半现代化的C version

答案 2 :(得分:2)

/* Count Leading Zeroes */

static uint8_t clzlut[256] = {
  8,7,6,6,5,5,5,5,
  4,4,4,4,4,4,4,4,
  3,3,3,3,3,3,3,3,
  3,3,3,3,3,3,3,3,
  2,2,2,2,2,2,2,2,
  2,2,2,2,2,2,2,2,
  2,2,2,2,2,2,2,2,
  2,2,2,2,2,2,2,2,
  1,1,1,1,1,1,1,1,
  1,1,1,1,1,1,1,1,
  1,1,1,1,1,1,1,1,
  1,1,1,1,1,1,1,1,
  1,1,1,1,1,1,1,1,
  1,1,1,1,1,1,1,1,
  1,1,1,1,1,1,1,1,
  1,1,1,1,1,1,1,1,
  0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0
};

uint32_t clz(uint32_t val)
{
  uint32_t accum = 0;

  accum += clzlut[val >> 24];
  accum += (accum == 8 ) ? clzlut[(val >> 16) & 0xFF] : 0;
  accum += (accum == 16) ? clzlut[(val >>  8) & 0xFF] : 0;
  accum += (accum == 24) ? clzlut[ val        & 0xFF] : 0;

  return accum;     
}

说明:

这通过将每个字节排列的前导零的数量存储为查找表来实现。您可以使用字节值来查找该值的前导零计数。由于该示例对unsigned int执行此操作,因此您移动并屏蔽四个单独的字节,并相应地累积查找。一旦我们找到一个设置的位,三元语句就用于停止累积。累积值为8,16或24意味着到目前为止没有找到设置位。

此外,一些架构对此具有硬件支持(作为指令)。汇编助记符通常称为“CLZ”或“BSR”。它们分别是“Count leading Zeroes”和“Bit Scan Reverse”的缩写。

答案 3 :(得分:0)

如果您认为Long.numberOfTrailingZeros速度很快(即JIT编译/优化以在可用时使用单个ASM指令),那么为什么不能简单地执行以下操作:

max(8,Long.numberOfTrailingZeros(val))

其中val是转换为Long的字节值。这也假设max()可用并再次优化以使用asm select或max指令。

理论上,在支持它的机器上,这些操作可以被JIT编译为两个汇编指令。