Language agnostic 检测整数中的单个一位流

Language agnostic 检测整数中的单个一位流,language-agnostic,binary,bit-manipulation,Language Agnostic,Binary,Bit Manipulation,我必须检查一个数字是否满足以下标准: 0x80000000 0x00000001 0xff000000 0x000000ff 0xffffffff 0x000ff000 在二进制中,所有一位必须是连续的 该数字必须至少设置一位 连续的一位可能从MSB开始,也可能在LSB结束,因此,如果数字由一个一位流和一个零位流组成,则它是完全有效的,反之亦然 我编写了一个代码,用于检查实际问题的这些条件(检查数据文件完整性) 它的工作没有问题,而且它对时间没有任何要求,但我是一个

我必须检查一个数字是否满足以下标准:

  0x80000000
  0x00000001
  0xff000000
  0x000000ff
  0xffffffff
  0x000ff000
  • 在二进制中,所有一位必须是连续的
  • 该数字必须至少设置一位
  • 连续的一位可能从MSB开始,也可能在LSB结束,因此,如果数字由一个一位流和一个零位流组成,则它是完全有效的,反之亦然
我编写了一个代码,用于检查实际问题的这些条件(检查数据文件完整性)

它的工作没有问题,而且它对时间没有任何要求,但我是一个老的有点颤抖的怪胎,喜欢这样的谜题,所以我试图想出一个更聪明的方法来检查单比特流

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

欢迎任何想法、二进制破解和部分解决方案


为了使我的要求更加明确,请举例说明:以下数字符合我的标准:

  0x80000000
  0x00000001
  0xff000000
  0x000000ff
  0xffffffff
  0x000ff000
以下数字没有(因为它们有多个连续的一个字符串):


0xf00000f这应该是您想要的

if(i == 0)
    return false;
while(i % 2 == 0) {
    i = i / 2;
}
return (i & (i + 1)) == 0;
N位整数(496表示32位整数)有
(N^2-N)/2
的可能性


您可以使用查找表。

如果您想要快速,基本算法将是:

  • 查找最低位集
  • 按最低位集的索引移位数字
  • 加1
  • 如果结果是二的幂和非零,那么成功 所有这些操作都是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); }
    
    编辑:将最终操作更新为零,但OP的算法要快得多,因为它都是常量操作(尽管溢出的计算是PITA)


    MSN

    我将使用bsr和bsf来确定数字中设置的最小和最大位。在此基础上,创建一个满足条件的有效数字。比较已知有效数字与实际数字是否相等。没有循环,只有一个比较

    伪代码:

    min_bit = bsf(number);
    max_bit = bsr(number);
    valid_number = ~(-1 << (max_bit - min_bit) ) << min_bit;
    return ( number == valid_number );
    
    min\u bit=bsf(数字);
    最大位=bsr(数字);
    
    valid_number=~-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+=最低\u位


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

    我在方法hasInsetZero中解决了几乎相同的问题:(并使用了其他几个位技巧)

    这是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)));
    }
    

    您将如何在表中搜索数字?这可能比只考虑数字的成本更高(数字可以存储在寄存器中,而不需要为查找表访问内存).由于内存访问的原因,二进制搜索和哈希表的成本可能比考虑数字本身要高。嗯。好主意。然而,出乎意料的是,我认为2K表的平均速度比暴力搜索慢(想想缓存未命中等).Oops。它对任何东西都不起作用。我的意思是按位and,而不是xor。是的,它对每个位集的数字都起作用。在这种情况下,I+1为零,而and为零。好的一个!比我的解决方案好得多。好的一个!我也会在x86上使用bsr和bsf(很好的指令,但没有人使用它们…)但是,我有一个嵌入式背景,而且大多数CPU都有一种或另一种扫描位的方式,它们只关心最高位(因此BSR很昂贵)。(来自于低功耗CPU没有除法指令的传统,顺便说一句。类似于将前导零计数为一个单周期指令会大大加快软件除法!)啊,通过消除计数尾随零,这比我的要好!尽管您希望使最低位=a&-a;MSN可以工作?a&(a-1)删除最低位,要将其隔离,需要a&(-a),或无符号a&(~a+1)。但更简单的是,a |(a-1)将所有尾随位设置为1。然后只需检查此数量+1是否为2的幂,请参阅我的解决方案。
    hasInsetZero: aMask
        | allOnes |
        allOnes := aMask bitOr: aMask - 1.
        ^(allOnes bitAnd: allOnes + 1) > 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)));
    }