int a = 12;
例如:12的二进制是1100,所以当右边的第3位被设置时,答案应该是3。
我想要a
的最后设置位的位置。谁能告诉我怎么能这样做。
注意:我只想要位置,这里我不想设置或重置该位。因此,它不会与stackoverflow上的任何问题重复。
答案 0 :(得分:10)
这个答案Unset the rightmost set bit告诉我们如何获取和取消设置最右边的设置位表示无符号整数或有符号整数表示为2的补码。
最右边设置位,
x & -x
// or
x & (~x + 1)
取消设置最右边的位,
x &= x - 1
// or
x -= x & -x // rhs is rightmost set bit
工作原理
x: leading bits 1 all 0
~x: reversed leading bits 0 all 1
~x + 1 or -x: reversed leading bits 1 all 0
x & -x: all 0 1 all 0
例如,让x = 112
,并选择8位以简化,但所有大小的整数都是相同的。
// example for get rightmost set bit
x: 01110000
~x: 10001111
-x or ~x + 1: 10010000
x & -x: 00010000
// example for unset rightmost set bit
x: 01110000
x-1: 01101111
x & (x-1): 01100000
答案 1 :(得分:7)
查找最低有效设置位的(从0开始)索引等效于计算给定整数有多少尾随零。根据您的编译器,有内置函数,例如gcc和clang support __builtin_ctz
。
对于MSVC,您需要实现自己的版本,this answer到另一个问题显示使用MSVC内在函数的解决方案。
鉴于您正在寻找基于1的索引,您只需要在ctz
的结果中加1,以达到您想要的效果。
int a = 12;
int least_bit = __builtin_ctz(a) + 1; // least_bit = 3
请注意,如果a == 0
,此操作未定义。此外,如果您使用long
和long long
代替int
,则应使用__builtin_ctzl
和__builtin_ctzll
。
答案 2 :(得分:6)
这里可以使用2s-complement的属性。
查找数字的2s补码的最快方法是获取最右边的位置并将所有内容翻转到左侧。
例如:考虑一个4位系统
4 = 0100
2s补充4 = 1100,其中只有-4
4&( - 4)= 0100。
请注意,只有一个设置位,最右边的设置位为4
同样,我们可以将此概括为n。
n&( - n)将只包含一个实际位于n的最右设置位位置的设置位
由于n&( - n)中只有一个设定位,因此它的功率为2
所以最后我们可以通过以下方式获得位位置:
答案 3 :(得分:4)
Knuth 7.1.3中有一个巧妙的技巧,您可以乘以一个“魔术”数字(通过蛮力搜索找到),该数字将数字的前几位映射到最右边每个位置的唯一值位,然后您可以使用一个小的查询表。这是针对nlopt library(MIT / expat许可)改编的32位值技巧的实现。
/* Return position (0, 1, ...) of rightmost (least-significant) one bit in n.
*
* This code uses a 32-bit version of algorithm to find the rightmost
* one bit in Knuth, _The Art of Computer Programming_, volume 4A
* (draft fascicle), section 7.1.3, "Bitwise tricks and
* techniques."
*
* Assumes n has a 1 bit, i.e. n != 0
*
*/
static unsigned rightone32(uint32_t n)
{
const uint32_t a = 0x05f66a47; /* magic number, found by brute force */
static const unsigned decode[32] = { 0, 1, 2, 26, 23, 3, 15, 27, 24, 21, 19, 4, 12, 16, 28, 6, 31, 25, 22, 14, 20, 18, 11, 5, 30, 13, 17, 10, 29, 9, 8, 7 };
n = a * (n & (-n));
return decode[n >> 27];
}
答案 4 :(得分:2)
您可以通过执行 n 的按位xor和(n&(n-1))
找到最右边设置位的位置int pos = n ^ (n&(n-1));
答案 5 :(得分:2)
可以使用以下公式获得n的最左边的位: n& 〜第(n-1)
这是有效的,因为当你计算(n-1)..你实际上是所有的零,直到最右边的位为1,最右边的位为0。 然后你拿不到它..它留给你以下: x =〜(来自原始数字的位)+(最右边的1位)+尾随零
现在,如果你做(n& x),你得到你需要的东西,因为n和x中唯一的1是最右边的位。
Phewwwww ..:sweat_smile:
http://www.catonmat.net/blog/low-level-bit-hacks-you-absolutely-must-know/ 帮助我理解这一点。
答案 6 :(得分:1)
检查a & 1
是否为0.如果是,请向右移动直到它不为零。移位的次数是右边的多少位是最右边的位。
答案 7 :(得分:1)
我继承了这个,注意它来自HAKMEM(试试here)。它适用于有符号和无符号整数,逻辑或算术右移。它也很有效率。
#include <stdio.h>
int rightmost1(int n) {
int pos, temp;
for (pos = 0, temp = ~n & (n - 1); temp > 0; temp >>= 1, ++pos);
return pos;
}
int main()
{
int pos = rightmost1(16);
printf("%d", pos);
}
答案 8 :(得分:1)
1- 减去1 表格编号:(a-1)
2-以否定表示:〜(a-1)
3-使用原始号码进行“ AND ”操作:
int last_set_bit = a&〜(a-1)
相减的原因是,当您求反时,它会将最后一位设置为1。
答案 9 :(得分:0)
您必须检查从索引0开始的所有32位并向左前进。如果您可以按位 - 并且a
在该位置有一位并返回非零值,则表示该位已设置。
#include <limits.h>
int last_set_pos(int a) {
for (int i = 0; i < sizeof a * CHAR_BIT; ++i) {
if (a & (0x1 << i)) return i;
}
return -1; // a == 0
}
在典型系统中,int将是32位,但即使sizeof a * CHAR_BIT
的大小不同,执行a
也能获得正确的位数
答案 10 :(得分:0)
参加 dbush 的解决方案,试试这个:
int rightMostSet(int a){
if (!a) return -1; //means there isn't any 1-bit
int i=0;
while(a&1==0){
i++;
a>>1;
}
return i;
}
答案 11 :(得分:0)
返回log2(((num-1)^ num)+1);
解释与例子:12 - 1100
num-1 = 11 = 1011
num ^(num-1)= 12 ^ 11 = 7(111)
num ^(num-1))+ 1 = 8(1000)
log2(1000)= 3(回答)。
答案 12 :(得分:0)
x&amp; 〜(x-1)隔离最低位为1。
答案 13 :(得分:0)
int main(int argc, char **argv)
{
int setbit;
unsigned long d;
unsigned long n1;
unsigned long n = 0xFFF7;
double nlog2 = log(2);
while(n)
{
n1 = (unsigned long)n & (unsigned long)(n -1);
d = n - n1;
n = n1;
setbit = log(d) / nlog2;
printf("Set bit: %d\n", setbit);
}
return 0;
}
结果如下。
Set bit: 0
Set bit: 1
Set bit: 2
Set bit: 4
Set bit: 5
Set bit: 6
Set bit: 7
Set bit: 8
Set bit: 9
Set bit: 10
Set bit: 11
Set bit: 12
Set bit: 13
Set bit: 14
Set bit: 15
答案 14 :(得分:-4)
试试这个
static