(数字)和(-数字)的含义
meaning of (number) & (-number)
(number) & (-number)
是什么意思?我已经搜索过它,但找不到含义
我想在 for 循环中使用i & (-i)
,例如:
for (i = 0; i <= n; i += i & (-i))
假设 2 的补码(或i
是无符号的),-i
等于~i+1
。
i & (~i + 1)
是提取最低设置位i
的技巧。
它之所以有效,是因为 +1 实际所做的是设置最低清除位,并清除低于该位的所有位。因此,在i
和~i+1
中设置的唯一位是i
中的最低设置位(即~i
中的最低清除位)。低于~i+1
的位在 中是清晰的,高于i
和~i
之间的位是不相等的。
在循环中使用它似乎很奇怪,除非循环体修改i
,因为i = i & (-i)
是一个幂等操作:做两次会再次得到相同的结果。
[编辑:在其他地方的评论中,您指出代码实际上是i += i & (-i)
。因此,对于非零i
,它的作用是清除i
的最低一组设置位,并设置高于该位的下一个清除位,例如 101100 -> 110000。对于没有高于最低设定位(包括i = 0
)的明确位的i
,它将i
设置为 0。因此,如果不是因为i
从0
开始,每个循环都会增加i
至少是前一个循环的两倍,有时甚至更多,直到最终它超过n
并中断或进入0
并永远循环。
在没有注释的情况下编写这样的代码通常是不可原谅的,但根据问题的领域,这可能是一个"明显"的值序列来循环。
假设负值使用 2 的补码。然后-number
可以计算为(~number)+1
,翻转位并加1。
例如,如果number = 92
.那么这就是它在二进制中的样子:
number 0000 0000 0000 0000 0000 0000 0101 1100
~number 1111 1111 1111 1111 1111 1111 1010 0011
(~number) + 1 1111 1111 1111 1111 1111 1111 1010 0100
-number 1111 1111 1111 1111 1111 1111 1010 0100
(number) & (-number) 0000 0000 0000 0000 0000 0000 0000 0100
从上面的例子中可以看出,(number) & (-number)
给你的位最少。
您可以看到在 IDE One 上在线运行的代码:http://ideone.com/WzpxSD
下面是一些 C 代码:
#include <iostream>
#include <bitset>
#include <stdio.h>
using namespace std;
void printIntBits(int num);
void printExpression(char *text, int value);
int main() {
int number = 92;
printExpression("number", number);
printExpression("~number", ~number);
printExpression("(~number) + 1", (~number) + 1);
printExpression("-number", -number);
printExpression("(number) & (-number)", (number) & (-number));
return 0;
}
void printExpression(char *text, int value) {
printf("%-20s", text);
printIntBits(value);
printf("n");
}
void printIntBits(int num) {
for(int i = 0; i < 8; i++) {
int mask = (0xF0000000 >> (i * 4));
int portion = (num & mask) >> ((7 - i) * 4);
cout << " " << std::bitset<4>(portion);
}
}
这里还有一个 C# .NET 中的版本:https://dotnetfiddle.net/ai7Eq6
我想我只是花点时间展示一下它是如何工作的。此代码为您提供最低设置位的值:
int i = 0xFFFFFFFF; //Last byte is 1111(base 2), -1(base 10)
int j = -i; //-(-1) == 1
int k = i&j; // 1111(2) = -1(10)
// & 0001(2) = 1(10)
// ------------------
// 0001(2) = 1(10). So the lowest set bit here is the 1's bit
int i = 0x80; //Last 2 bytes are 1000 0000(base 2), 128(base 10)
int j = -i; //-(128) == -128
int k = i&j; // ...0000 0000 1000 0000(2) = 128(10)
// & ...1111 1111 1000 0000(2) = -128(10)
// ---------------------------
// 1000 0000(2) = 128(10). So the lowest set bit here is the 128's bit
int i = 0xFFFFFFC0; //Last 2 bytes are 1100 0000(base 2), -64(base 10)
int j = -i; //-(-64) == 64
int k = i&j; // 1100 0000(2) = -64(10)
// & 0100 0000(2) = 64(10)
// ------------------
// 0100 0000(2) = 64(10). So the lowest set bit here is the 64's bit
它对无符号值的工作方式相同,结果始终是最低设置位的值。
给定您的循环:
for(i=0;i<=n;i=i&(-i))
没有设置位 (i=0
),因此您将为此操作的增量步骤返回 0。因此,除非修改n=0
或i
,否则这个循环将永远持续下去。
运算i & -i
用于隔离相应整数的最低有效非零位。
-
在二进制表示法中,
num
可以表示为a1b
,其中a
表示最后一位之前的二进制数字,b
表示最后一位之后的零。 -
-num
等于(a1b)¯ + 1 = a¯0b¯ + 1
。b
由所有零组成,因此b¯
由所有零组成。-num = (a1b)¯ + 1
=>a¯0b¯ + 1
=>a¯0(0…0)¯ + 1
=>¯0(1…1) + 1
=>a¯1(0…0)
=>a¯1b
-
现在,
num & -num
=>a1b & a¯1b
=>(0..0)1(0..0)
例如,如果 i = 5
| iteration | i | last bit position | i & -i|
|-------- |--------|-------- |-----|
| 1 | 5 = 101 | 0 | 1 (2^0)|
| 2 | 6 = 110 | 1 | 2 (2^1)|
| 3 | 8 = 1000 | 3 | 8 (2^3)|
| 4 | 16 = 10000 | 4 | 16 (2^4)|
| 5 | 32 = 100000 | 5 | 32 (2^5)|
此操作主要用于二叉索引树中上下移动树
PS:由于某种原因,堆栈溢出将表视为代码:(
- 比较并显示使用最小值(a,b)和最大值(a、b)升序排列的4个数字
- 为什么随机数生成器不在void函数中随机化数字,而在main函数中随机化
- 检查输入是否不是整数或数字
- 如何(从固定列表中)选择一个数字序列,该序列将与目标数字相加
- 如何用数字处理log(0)
- 最高有效数字侧的第N位
- 如何获取一个数字的前3位
- 查找最接近的大于当前数字的数字的索引
- 找到两对数字,使它们的乘积的绝对差最小化
- 我想做一个彼此不同但重复出现的数字
- 将数字转换为字母(例如:123 转换为一二三)
- C++如何计算用户输入的数字中的偶数位数
- 如何在C++中确定文本文件中的元素是字符还是数字
- 打印数字图案
- C++问题:用户认为数字1-100,程序提出问题不超过6次即可得到答案。无法正确
- 如何检查一个c++字符串中有多少相同的字符/数字
- 求出有多少个数字是完美平方,而sqrt()是L,R范围内的素数
- 将数字打印成文字
- 当使用比格式支持的精度更高的精度来显示数字时,会写出什么数据
- 在将数字随机生成为数组期间从内存输出随机数的数组