LeetCode Reverse Integer题Java实现异常输出原因求解
问题根因分析
首先明确Java中int的取值规则:32位有符号整数的取值范围是[-2^31, 2^31 - 1],也就是[-2147483648, 2147483647],最小负数-2147483648没有对应的正int值,对int类型的-2147483648执行取负操作会发生静默溢出,最终结果仍然是-2147483648。
原代码错误执行流程
输入x为-2147483648时,原代码执行逻辑如下:
- 初始化
x = -2147483648(int类型),negative = false - 进入
x<0的分支,negative设为true,执行x = 0 - x:因为x是int类型,取负结果2147483648超过int最大值,溢出后x仍然为-2147483648,没有得到预期的正数 - 执行
long k = x:将溢出后的int值-2147483648转成long类型,k的值为-2147483648 - 反转k时,因为k是负数,每一步取模得到的都是负数,最终得到的
reverseNum为-8463847412 - 判断
reverseNum>Integer.MAX_VALUE:负数显然不满足该条件,进入else分支 - 因为
negative为true,执行0 - (int)reverseNum:将long类型的-8463847412转成int时再次溢出,得到126087180,取负后就是你看到的错误输出-126087180
移动语句后符合预期的原因
你将long k = x移到第二行(x初始化之后)时,相当于在修改x之前,就把原始的x值保存到了long类型的k中,后续对int类型x的取负溢出不会影响k的值。long类型的取值范围远大于int,对long类型的-2147483648做取负操作不会溢出,会得到正确的正数2147483648:
- 反转后得到的
reverseNum为8463847412,明显大于Integer.MAX_VALUE,所以会直接输出0,符合预期。
修复建议
不要对int类型的输入直接做取负操作,应该先将其转为long类型后再处理符号,避免溢出:
int x = -2147483648; boolean negative = x < 0; // 先转long再处理符号,避免溢出 long k = Math.abs((long)x); long reverseNum = 0; while(k!=0){ reverseNum *= 10; reverseNum += k % 10; k /= 10; } if( reverseNum>Integer.MAX_VALUE) System.out.println(0); else System.out.println(negative ? 0-(int)reverseNum : (int)reverseNum);
内容的提问来源于stack exchange,提问作者Roshan Choudhary
相关产品推荐
相关产品推荐

