C++计算Hamming weight时出现有符号整数溢出问题求助
先看你的代码逻辑:通过定位整数的最高位1,递归减去该位对应的值来统计1的个数。问题出在while(a<=(float)n/2)这个循环条件上,我们针对输入n=2147483645的情况一步步拆解:
32位有符号int的取值范围:通常C++中
int是32位有符号整数,范围是-2^31到2^31-1(即-2147483648到2147483647)。2147483645是接近最大值的数,二进制为01111111 11111111 11111111 11111101。(float)n/2的精度丢失问题:
float类型的尾数仅23位(加隐含位共24位),无法精确表示所有大于2^24的整数。当把2147483645转为float时,会被近似为最接近的可表示值2147483648.0,因此(float)n/2的结果是1073741824.0。溢出触发的过程:循环中
a从1开始每次乘2,当a增长到1073741824时,判断条件a <= 1073741824.0成立,于是执行a*=2。但1073741824 * 2 = 2147483648,这个值超出了32位有符号int的最大值2147483647,触发有符号整数溢出(C++中属于未定义行为),进而抛出运行时错误。改成a<=n/2正常的原因:
n/2是整数除法,2147483645 / 2的结果是1073741822(整数除法会截断小数部分)。当a增长到1073741824时,1073741824 <= 1073741822不成立,循环直接终止,不会执行a*=2的操作,自然避免了溢出。
另外补充一种更高效且无溢出风险的汉明重量写法,利用n &= n-1消除最低位1的特性:
class Solution { public: int hammingWeight(int n) { int count = 0; while (n != 0) { n &= n - 1; count++; } return count; } };
内容的提问来源于stack exchange,提问作者simply lemon

