关于Fenwick树(BIT)索引计算的C++版本兼容性问题
Fenwick树(BIT) read函数的位运算实现问题解析
问题1:C++20之前,idx[i+1] = idx[i] - (idx[i] & -idx[i]);是否属于不正确的实现?
是。C20之前的标准没有强制有符号整数采用补码表示,原码、反码都是合法的实现方式。这段代码的核心逻辑完全依赖补码下“负数等于按位取反加1”的特性,才能让idx[i] & -idx[i]提取出当前值的最低有效非零位掩码。如果编译器用非补码的有符号整数表示(比如原码),-idx[i]的位模式会完全偏离预期,&运算的结果无法得到正确掩码,最终导致read函数生成的索引序列错误。所以这段代码在C20之前属于不可移植的不正确实现,只能在默认用补码的编译器上侥幸运行。
问题2:C++20标准下,上述代码是否为正确实现?
是。C++20强制所有有符号整数类型必须使用补码表示,此时-idx[i]的位模式严格等于~idx[i] + 1,idx[i] & -idx[i]必然能精准提取当前值的最低有效非零位掩码。以示例中的idx=13(二进制00001101)为例:
13 & -13等价于00001101 & 11110011(补码下-13的位模式),结果是00000001,13-1=12,符合要求;- 12的二进制是
00001100,12 & -12是00001100 & 11110100,结果是00000100,12-4=8,完全匹配预期的索引序列。
因此这段代码在C++20下是完全正确的实现。
问题3:无符号类型下,是否可使用idx[i+1] = idx[i] - (((~idx[i]) + 1) & idx[i])?
可以,但没必要写这么冗余。无符号整数的位运算在C++所有版本中都定义明确,~idx[i] + 1等价于无符号语义下的-idx[i](无符号减法是模2^N运算,-x的结果就是UINT_MAX - x + 1,和按位取反加1完全一致)。所以((~idx[i]) + 1) & idx[i]和idx[i] & -idx[i]的结果完全相同,直接写idx[i] - (idx[i] & -idx[i])在无符号类型下既简洁又正确,效果和长写法完全一致。
内容的提问来源于stack exchange,提问作者mbang
相关产品推荐
相关产品推荐

