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