C++ long long计算1e15范围值报signed integer overflow错误求解
问题原因
64位有符号整型long long的最大可表示值为$2^{63}-1 \approx 9.2\times10{18}$,代码中直接计算`n*n`时,当n取到题目约定的上限$10{15}$,乘积结果为$10^{30}$,远超出long long的存储范围,直接触发有符号整数溢出——这是C++标准中明确的未定义行为,会导致计算结果完全错误、程序崩溃等不可预期的问题。
最优修复方案:先代数化简表达式,从根源消除溢出风险
原有计算式可以通过代数化简完全去掉平方项,根本不需要执行大数值乘法,自然不会出现溢出:
- 当n为偶数时,设n=2k,代入原式化简可得结果为
n/2 - 当n为奇数时,设n=2k+1,代入原式化简可得结果为
-(n+1)/2
给出的测试输入208170109961052是偶数,除以2的结果正好是预期输出104085054980526,完全匹配。
化简后的代码如下,全程没有高风险的大数值乘法运算,哪怕n取到long long的上限也不会溢出:
#include <iostream> using namespace std; int main() { long long n; cin >> n; if (n % 2) { cout << -(n + 1) / 2 << '\n'; } else { cout << n / 2 << '\n'; } return 0; }
备选修复方案:使用128位整型承接中间计算结果
如果不想修改原有计算逻辑,可以用主流C++编译器(GCC、Clang)支持的128位整型__int128存储中间乘积结果,__int128最大可表示值约为$1.7\times10{38}$,完全可以容纳$10{15}$的平方结果。注意__int128不支持直接输入输出,计算完成后将结果转回long long类型再输出即可。
修改后的代码如下:
#include "bits/stdc++.h" using namespace std; int main() { long long n; cin >> n; if (n % 2) { __int128 a = n-1; __int128 b = (n+1)/2; long long res = ( (a*a)/4 + (n-1)/2 ) - (b*b); cout << res << '\n'; } else { __int128 a = n; __int128 b = n/2; long long res = ( (a*a)/4 + n/2 ) - (b*b); cout << res << '\n'; } return 0; }
注意:
__int128不属于C++标准规定的内置类型,在MSVC等部分编译器上无法使用,优先选择代数化简的方案,兼容性最好、运行效率最高。
内容的提问来源于stack exchange,提问作者Nazmus Sakib Sibly
相关产品推荐
相关产品推荐

