如何识别long类型溢出错误?代码未抛出RuntimeException
问题分析与修复方案
核心问题1:缓存的负数结果直接返回,未触发异常
你的binomialCoefficient方法中,当缓存值不为0时直接返回,没有检查该值是否为负数(溢出结果)。如果某次计算溢出后将负数存入缓存,后续调用会直接返回这个负数,不会抛出异常。
核心问题2:main方法中变量未正确初始化
如果第一个try块捕获到输入异常(比如非数字输入),n、k、cache会处于未初始化/null状态,后续调用binomialCoefficient会引发额外异常,干扰溢出异常的处理。
修复后的代码
import java.util.Scanner; public class combinations { public static void main(String[] args) { Scanner sc = new Scanner(System.in); while(sc.hasNextLine()){ String[] input = sc.nextLine().split(" "); if(input.length==2){ long n = 0; long k = 0; long[][] cache = null; try { n = Long.parseLong(input[0]); k = Long.parseLong(input[1]); // 优化组合数计算:C(n,k)=C(n,n-k),减少递归次数 k = Math.min(k, n - k); cache = new long[(int)(n + 1)][(int)(k + 1)]; } catch (Exception e) { System.out.println("输入无效,请输入两个合法的整数"); continue; } try{ System.out.println(binomialCoefficient(n, k, cache)); } catch (RuntimeException e) { System.out.println(e.getMessage()); } } else { System.out.println("输入格式错误,请输入两个空格分隔的整数"); } } sc.close(); } public static long binomialCoefficient(long n, long k, long[][] cache) { if (k == 0 || k == n) { return cache[(int)n][(int)k] = 1; } // 检查缓存值,若为负数说明之前已溢出,直接抛异常 if (cache[(int)n][(int)k] != 0) { if (cache[(int)n][(int)k] < 0) { throw new RuntimeException("Overflow occured"); } return cache[(int)n][(int)k]; } long left = binomialCoefficient(n-1, k-1, cache); long right = binomialCoefficient(n-1, k, cache); // 加法前检查是否会溢出,比溢出后检查更严谨 if (left > Long.MAX_VALUE - right) { cache[(int)n][(int)k] = -1; // 标记溢出 throw new RuntimeException("Overflow occured"); } cache[(int)n][(int)k] = left + right; return cache[(int)n][(int)k]; } }
关键修复点
- 缓存检查增强:返回缓存值前先判断是否为负数,若为负数直接抛出溢出异常。
- 加法前溢出检查:在计算
left + right前,判断left是否大于Long.MAX_VALUE - right,提前发现溢出,避免产生负数结果后再处理。 - 组合数优化:利用
C(n,k)=C(n,n-k)减少递归深度和计算量,同时缩小缓存数组的大小(只需到k即可,无需到n)。 - 输入异常处理优化:输入无效时直接提示并跳过后续计算,避免未初始化变量引发的问题。
内容的提问来源于stack exchange,提问作者a2s4342
相关产品推荐
相关产品推荐

