大输入下五数选四求和最值程序输出错误求助
问题排查与修复
错误根源
代码在大输入下结果错误的核心原因是整数溢出:
- 输入的数组元素是
int类型,而四个大整数相加的结果会超过32位int的最大值(2^31-1 = 2147483647),导致int加法运算溢出,产生错误的中间值,再赋值给unsigned long int时已经无法恢复正确结果。 - 比如输入中最大的四个数求和:
623958417 + 467905213 + 714532089 + 938071624 = 2744467343,远大于32位int的上限,溢出后会变成负数,转成unsigned long int就会显示成超大的错误数值(如你看到的18446744072159051663)。
修复方案
以下两种方案均可解决问题,推荐第二种更简洁高效的实现:
方案一:修正现有代码的溢出问题
在计算每个四数之和时,先将int类型的数组元素转换为unsigned long int再进行加法运算,避免中间溢出:
void miniMaxSum(int arr_count, int *arr) { unsigned long int sum1, sum2, sum3, sum4, sum5, max, min; int i; // 每个元素先转成unsigned long再相加,避免int溢出 sum1 = (unsigned long)arr[0] + arr[1] + arr[2] + arr[3]; sum2 = (unsigned long)arr[4] + arr[1] + arr[2] + arr[3]; sum3 = (unsigned long)arr[0] + arr[4] + arr[2] + arr[3]; sum4 = (unsigned long)arr[0] + arr[1] + arr[4] + arr[3]; sum5 = (unsigned long)arr[0] + arr[1] + arr[2] + arr[4]; min = max = sum1; unsigned long int sumall[5] = { sum1, sum2, sum3, sum4, sum5 }; for (i = 0; i < arr_count; i++) { if (sumall[i] > max) { max = sumall[i]; } if (sumall[i] < min) { // 取消else if,逻辑更严谨,避免漏判 min = sumall[i]; } } printf("%lu %lu", min, max); }
方案二:优化实现逻辑(推荐)
不需要计算五个四数之和,而是先计算五个数的总和,再通过总和推导结果:
- 最小值 = 总和 - 数组中的最大值
- 最大值 = 总和 - 数组中的最小值
这种方式只需一次遍历,代码更简洁,也从根源避免了溢出问题:
void miniMaxSum(int arr_count, int *arr) { unsigned long total_sum = 0; int min_val = arr[0], max_val = arr[0]; for (int i = 0; i < arr_count; i++) { total_sum += (unsigned long)arr[i]; // 转换类型后累加,避免溢出 if (arr[i] < min_val) { min_val = arr[i]; } if (arr[i] > max_val) { max_val = arr[i]; } } unsigned long min_sum = total_sum - max_val; unsigned long max_sum = total_sum - min_val; printf("%lu %lu", min_sum, max_sum); }
测试验证
用你提供的输入256741038 623958417 467905213 714532089 938071624测试修复后的代码,正确输出应为:
2063136757 2744467343
内容的提问来源于stack exchange,提问作者Yash Kasle
相关产品推荐
相关产品推荐

