C++ 计算每4次方的倍数
给定一个数,n,我需要有效地找出这个数是给定数的所有4次幂的倍数 例如:C++ 计算每4次方的倍数,c++,bit-manipulation,bitwise-operators,C++,Bit Manipulation,Bitwise Operators,给定一个数,n,我需要有效地找出这个数是给定数的所有4次幂的倍数 例如: 16是4和16的倍数,因此结果为2 64是4、16和64的倍数,因此结果为3 256是4、16、64和256的倍数,因此结果为4 14不是4的任何幂的倍数,因此结果为0 35不是4的任何幂的倍数,因此结果为0 按位操作是首选,这是在一个非常紧密的循环中,因此它位于需要高效的瓶颈内。目前我的代码是显而易见的答案,但我必须相信,有一种更为数学化的方法可以用更少的步骤计算出结果: power = 4; while (powe
- 16是4和16的倍数,因此结果为2
- 64是4、16和64的倍数,因此结果为3
- 256是4、16、64和256的倍数,因此结果为4
- 14不是4的任何幂的倍数,因此结果为0
- 35不是4的任何幂的倍数,因此结果为0
power = 4;
while (power < n) {
result += !(n & (power - 1));
power *= 4;
}
power=4;
while(功率
数学方法是一直除以4
,直到结果不再可除以4
如果您真的想使用逐位操作,可以使用技术来计算尾随零位的数量(即值可被2
整除的次数)。这些可以调整为对尾随位进行计数(即,可被4而不是2的幂整除)
请注意,您将需要使用无符号
值,以避免出现某些未定义或未指定的行为
我不同意你的说法,即按位运算将有助于更有效的解决方案。在没有测试的情况下,它不是给定的,特别是在现代编译器中。可以使用对数。在谷歌上快速搜索“FastLog2C++”可以找到一长串的想法。然后你的答案是log2(x)/2,如果你只想得到4的精确幂的答案,你必须找到一些方法来确保你的结果是一个整数 如果您正在为x86处理器编程,则可以使用BitScanForward和BitScanReverse查找设置的位,并使用它计算log2。以下代码在VisualStudio中工作,对于GCC或其他代码,还有其他方法进行内联汇编
uint32_t exact_power_of_4_scan(uint32_t num)
{
unsigned long reverse;
unsigned long forward;
if (!_BitScanReverse(&reverse, num)) return 0;
_BitScanForward(&forward, num);
if (reverse != forward) return 0; // makes sure only a single bit is set
if (reverse & 0x1) return 0; // only want every other power of 2
return reverse / 2;
}
如果您需要一个可移植的解决方案,表查找可能是一种方法,但更为复杂
uint8_t not_single_bit[256] = {
1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1,
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 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, 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, 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, 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,
};
uint8_t log2_table[256] = {
0, 0, 1, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0,
4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5, 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,
6, 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,
7, 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 exact_power_of_2(uint32_t num)
{
auto a = not_single_bit[num & 0xff];
auto b = not_single_bit[(num >> 8) & 0xff];
auto c = not_single_bit[(num >> 16) & 0xff];
auto d = not_single_bit[(num >> 24) & 0xff];
if (a + b + c + d != 3) {
return 0;
}
if (!a) {
return log2_table[num & 0xff];
}
if (!b) {
return log2_table[(num >> 8) & 0xff] + 8;
}
if (!c) {
return log2_table[(num >> 16) & 0xff] + 16;
}
return log2_table[(num >> 24) & 0xff] + 24;
}
uint32_t exact_power_of_4(uint32_t num)
{
auto ret = exact_power_of_2(num);
if (ret & 0x1) return 0;
return ret / 2;
}
两者都是线性算法。第一个可能会击败几乎任何
num
值的循环,但我还没有测试它。第二种可能只适用于较大的num
s 不错的想法,它有点疯狂,但它确实摆脱了分支循环,并且对于n的高值可能更有效。将代码添加到您的答案中,我将接受它:int temp=BSR(n);值=!(n&((11);BSR=位扫描反转