在解决了LeetCode的一些C ++问题之后,我遇到了Reverse Integer,并意识到我无法真正掌握如何处理整数溢出。
问题很简单,并且在于反转整数(例如123-> 321)。现在,困难的部分是遵守以下限制:
假设我们正在处理的环境只能存储32位有符号整数范围内的整数:[− 2 31 ,2 31 − 1]。出于这个问题的目的,假设您的函数在反向整数溢出时返回0
我所做的是:
int reverse(int x) {
int temp = 0;
while(x != 0){
// pop
int pop = x%10;
x /= 10;
if(temp < (INT_MIN - pop)/10 || temp > (INT_MAX - pop)/10){
return 0;
}
else{
// push
temp = temp*10 + pop;
}
}
return temp;
}
不幸的是,该代码不能防止溢出。我在做什么错了?
答案 0 :(得分:6)
pop
的符号是实现定义的(在C ++ 11之前),如果INT_MIN - pop
为负,则将导致溢出。因此,让我们首先将问题简化为正整数:
if (x == INT_MIN) // INT_MIN cannot be inverted, handle it separately
return 0;
const int sign = (x < 0) ? -1 : 1;
x *= sign;
溢出条件是:
10 * temp + pop > INT_MAX
经过简单的数学运算,我们得到:
temp > (INT_MAX - pop) / 10
此处pop
始终为非负数,因此INT_MAX - pop
不会溢出。最终结果是sign * temp
。因为temp
为正,所以-temp
不会溢出(如果temp
为负,则可能会溢出)。
答案 1 :(得分:0)
看来问题出在逻辑上。由于temp
已初始化为0
,因此pop
无需输入条件。因此,只需编写if(temp < (INT_MIN)/10 || temp > (INT_MAX)/10)
。
最终代码如下,
int reverse(int x) {
int temp = 0;
while(x != 0){
// pop
int pop = x%10;
x /= 10;
if(temp < (INT_MIN)/10 || temp > (INT_MAX)/10){
return 0;
}
else{
// push
temp = temp*10 + pop;
}
}
return temp;
}
答案 2 :(得分:0)
我发现在光盘上显示二进制补码表示非常有帮助。
这里是 4 位整数的表示。最大值为 2^3-1 = 7。
对于 32 位整数,我们将看到最大值为 2^31-1。
当我们将2^31-1加1时:顺时针移动一个,显然是-2^31,称为整数溢出
在您的情况下,当您反转 2^31 时会发生溢出,当您反转需要获得 2^31,但它不存在并且您需要返回 0(如问题说明中所问)
参考:https://courses.cs.washington.edu/courses/cse351/17wi/sections/03/CSE351-S03-2cfp_17wi.pdf