(number & -number) 在位编程中是啥意思? [复制]

Posted

技术标签:

【中文标题】(number & -number) 在位编程中是啥意思? [复制]【英文标题】:What does (number & -number) mean in bit programming? [duplicate](number & -number) 在位编程中是什么意思? [复制] 【发布时间】:2016-06-22 00:51:11 【问题描述】:

例如:

int get(int i) 
    int res = 0;
    while (i) 
        res = (res + tree[i]) % MOD;
        i -= ( (i) & (-i) );
    
    return res;

树更新函数:

void update(int i, int val) 
    while (i <= m) 
        tree[i] = (tree[i] + val) % MOD;
        i += ( (i) & (-i) );
    

您能否解释一下他们在代码中使用( (i) &amp; (-i) ) 做了什么?

【问题讨论】:

i &amp; (-i) 是设置的最低位(即最右边的1)。 如果你想看看它是如何工作的,可以考虑一个有符号数n(用来表示-n)的twos-complement,如果你 使用n 不要指望自己发明这样的技巧。这些想法被复制的次数远远多于被发明出来的次数。 @PTwr - 第一个链接专门处理 javascript。虽然代码相似并且可以使用相同的技巧,但我不确定会有多少好处。一个体面的 C++ 编译器无论如何都会执行许多这些优化。我很想看看在 C++ 中使用这些技巧的速度比较。 良好的做法是建议将此类 hack 放在具有自记录名称(例如 least_significant_bit_set)的内联函数中。 【参考方案1】:

让我假设负值使用二进制补码表示。 在这种情况下,-i 可以计算为(~i)+1(翻转位,然后加 1)。

例如,让我考虑i = 44。然后,在二进制中,

i           = 0000 0000 0000 0000 0000 0000 0010 1100
~i          = 1111 1111 1111 1111 1111 1111 1101 0011
-i = (~i)+1 = 1111 1111 1111 1111 1111 1111 1101 0100
(i) & (-i)  = 0000 0000 0000 0000 0000 0000 0000 0100

如您所见,可以使用(i) &amp; (-i) 计算最小位 1。

【讨论】:

感谢您的解释。现在我完全明白了:) 这不是依赖于实现吗?我猜想所有当前的编译器都对负数使用二进制补码,但是没有人阻止编译器或体系结构以不同的方式执行它,这可能会导致未定义的行为。 @vsz:C 标准明确允许这样做,事实上,有符号整数可以有陷阱表示(如负零),所以这很适合 UB 领域。当然,-i 已经是潜在的 UB,因为 i 可能是最大的负整数,给你有符号整数溢出(这也是未定义的)。 工作代码示例见:***.com/a/36046076/984780【参考方案2】:

如果有人也想要更一般的证明,

假设x 的格式为a10k(这里的意思是一些位串a,后跟一个1,然后是k 个零)。

-x(根据定义)与~x + 1 相同,所以

x & -x =(填写) a10k & -(a10k) = (def. of negation) a10k & ~(a10k) + 1 = (应用反转) a10k & ~a01k + 1 = (加 1) a10k & ~a10k =(某事物与其逆事物之间的与) 0w10k

所以我们只剩下我们认为存在的最右边的一个 1。

关于x形式的假设忽略了x = 0的情况,在这种情况下结果显然仍然为零。

【讨论】:

【参考方案3】:

这两个函数是Binary index tree (Fenwick tree) 数据结构的修改实现。 这里有两张图片来补充 MikeCAT 的答案,显示 i 变量如何针对不同的值进行更新。“get”函数: 为简化表示,假设函数输入的最大值为 15。 编号为t的节点代表树数组中的tree[t]。 如果您为 i 调用 get 函数,则返回值是 tree[i] 的总和加上所有 tree 的总和它们在数组中的索引是图片中 i 的父元素的数组元素,但零除外。 以下是一些示例:

get(15) = tree[15] + tree[14] + tree[12] + tree[8]
get(14) = tree[14] + tree[12] + tree[8]
get(13) = tree[13] + tree[12] + tree[8]
get(12) = tree[12] + tree[8]
get(11) = tree[11] + tree[10] + tree[8]
get(10) = tree[10] + tree[8]
get(9) = tree[9] + tree[8]
get(8) = tree[8]
get(7) = tree[7] + tree[6] + tree[4]
get(6) = tree[6] + tree[4]
get(5) = tree[5] + tree[4]
get(4) = tree[4]
get(3) = tree[3] + tree[2]
get(2) = tree[2]

上图中节点标签上的数字具有这样一个属性,即每个节点的父节点是该节点标签减去最不重要的一个 1(在@MikeCAT 答案上解释得很好)“更新”功能: 为简单起见,假设 tree 数组的最大长度为 16。update 功能有点复杂。 它将 val 添加到 tree[i] 和所有 tree 元素,它们的索引是带有标签 i 的节点的父节点> 在图片中。

update(16, val) --> tree[16] += val;
update(15, val) --> tree[15] += val, tree[16] += val;
update(14, val) --> tree[14] += val, tree[16] += val;
update(13, val) --> tree[13] += val, tree[14] += val; tree[16] += val;
update(12, val) --> tree[12] += val, tree[16] += val;
update(11, val) --> tree[11] += val, tree[12] += val, tree[16] += val;
update(10, val) --> tree[10] += val, tree[12] += val, tree[16] += val;
update(9, val)  --> tree[9] += val, tree[10] += val, tree[12] += val, tree[16] += val;
update(8, val)  --> tree[8] += val, tree[16] += val;
update(7, val)  --> tree[7] += val, tree[8] += val, tree[16] += val;
update(6, val)  --> tree[6] += val, tree[8] += val, tree[16] += val;
update(5, val)  --> tree[5] += val, tree[6] += val, tree[8] += val, tree[16] += val;
update(4, val)  --> tree[4] += val, tree[8] += val, tree[16] += val;
update(3, val)  --> tree[3] += val, tree[4] += val, tree[8] += val, tree[16] += val;
update(2, val)  --> tree[2] += val, tree[4] += val, tree[8] += val, tree[16] += val;
update(1, val)  --> tree[1] += val, tree[2] += val, tree[4] += val, tree[8] += val, tree[16] += val;

【讨论】:

以上是关于(number & -number) 在位编程中是啥意思? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

位运算————两整数之和

如何在位图中加载具有相对路径的图像

在位图上绘制文本失败

(number & -number) 在位编程中是啥意思? [复制]

在位图上绘制对角线文本

在位图上使用 DrawText() 时文本旋转?