检测整数内的单个一位流

时间:2009-01-20 19:01:11

标签: language-agnostic binary bit-manipulation

如果符合以下条件,我必须检查一个数字:

  • 以二进制形式显示,所有一位必须是连续的。
  • 该数字必须至少设置一位。
  • 连续的一位可以在MSB处开始或在LSB处结束,因此如果该数字由单个一位流后跟零位流组成,则完全有效,反之亦然。

我编写了一个代码,用于检查实际问题的这些条件(检查数据文件的完整性)。

它可以毫无问题地工作,除了时间紧迫之外什么都没有,但我是一个古老的比特狂热的怪物并喜欢这样的谜题,所以我试图想出一个更聪明的方法来检查单一 - 比特流。

字符串被零包围的情况很容易,但是那个不能处理特殊情况。

欢迎任何想法,二元黑客和部分解决方案!


为了使我的要求更清楚一些例子:以下数字符合我的标准:

  0x80000000
  0x00000001
  0xff000000
  0x000000ff
  0xffffffff
  0x000ff000

以下数字不会(因为它们有多个连续的字符串):

  0xf00000f <- one-bit streams should not wrap-around at 2^n
  0x0001700 <- a trivial example.
  0x0000000 <- no one bit at all.

7 个答案:

答案 0 :(得分:3)

bool isOK(uint val) {
   while (val != 0 && (val & 1u) == 0) val >>= 1;
   if (val == 0) return false;
   while (val != 0 && (val & 1u) == 1) val >>= 1;
   return val == 0;
}

; x86 assembly
mov eax, THE_NUMBER ; store the number in eax
bsf ecx, eax
jz .notok
mov edi, 1
shl edi, cl
mov esi, eax
add esi, edi
test esi, eax
jnz .notok
mov eax, 1
jmp .end
.notok:
mov eax, 0
.end: ; eax = 1 if satisfies the criteria, otherwise it's 0

答案 1 :(得分:3)

这应该做你想要的。

if(i == 0)
    return false;
while(i % 2 == 0) {
    i = i / 2;
}
return (i & (i + 1)) == 0;

答案 2 :(得分:2)

我在方法hasInsetZero中解决了与http://smallissimo.blogspot.fr/2012/04/meteor-contest-part-3-reducing.html几乎相同的问题:(并使用了其他几个技巧)

hasInsetZero: aMask
    | allOnes |
    allOnes := aMask bitOr: aMask - 1.
    ^(allOnes bitAnd: allOnes + 1) > 0

它是Smalltalk代码,但是用C语言翻译(我们需要否定并关注0),那就是:

int all_set_bits_are_consecutive( x )
/* return non zero if at least one bit is set, and all set bits are consecutives */
{
   int y = x | (x-1);
   return x && (! (y & (y+1)));
}

答案 3 :(得分:1)

假设您想要快速,基本算法将是:

  1. 找到最低位集。
  2. 按最低位设置的索引移位数。
  3. 添加1。
  4. 如果结果是2的幂且非零,则成功!
  5. 所有这些操作都是O(1)或O(log(整数位宽)),如下所示:

    unsigned int lowest_power_of_2(unsigned int value) 
    { return value & -value; }
    
    unsigned int count_bits_set(unsigned int value) 
    { /* see counting bits set in parallel */ }
    
    unsigned int lowest_bit_set_or_overflow_if_zero(unsigned int value)
    { return count_bits_set(lowest_power_of_2(value) - 1); }
    
    unsigned int is_zero_or_power_of_2(unsigned int value)
    { return value && (value & (value - 1))==0; }
    
    bool magic_function(unsigned in value)
    { return is_zero_or_power_of_2((value >> (lowest_bit_set_or_overflow_if_zero(lowest_power_of_2(value)))) + 1); }
    

    编辑:更新的最终操作占0,但是OP的算法要快得多,因为它都是常量操作(尽管溢出会占用PITA)。

    MSN

答案 4 :(得分:1)

我会使用bsr和bsf来确定数字中设置的最小和最大位数。从那里,创建一个满足标准的有效数字。将已知有效数字与实际数字进行比较以获得相等性。没有循环,只有一个比较。

伪码:

min_bit = bsf(number);
max_bit = bsr(number);
valid_number = ~(-1 << (max_bit - min_bit) ) << min_bit;
return ( number == valid_number );

答案 5 :(得分:1)

我正在进行中的版本。不作为答案,只是为了提供更多的想法并记录我当前的方法:

int IsSingleBitStream (unsigned int a)
{
  // isolate lowest bit:
  unsigned int lowest_bit = a & (a-1);

  // add lowest bit to number. If our number is a single bit string, this will
  // result in an integer with only a single bit set because the addition will     
  // propagate up the the highest bit. We ought to end up with a power of two.
  a += lowest_bit;

  // check if result is a power of two:
  return (!a || !(a & (a - 1)));
}

如果以下行:

,则此代码无效

a + = lowest_bit

溢出。另外,我不确定如果有多个位字段,我的“隔离单位”代码是否有效。

答案 6 :(得分:0)

N位整数有(N^2 - N) / 2种可能性(32位为496)。

您可以使用查找表。