C语言整数三次方计算异常:为何pow函数可获正确值?
问题原因分析:int中间运算溢出导致结果错误
这问题的核心不是long long溢出,而是中间运算全是用int类型执行的,早就溢出了!
咱们一步一步拆解:
- 你的函数参数
n是int类型,假设是常见的32位int,最大值是2147483647。输入的2015671确实小于这个值,所以n本身没问题。 - 但计算
n*n*n的时候,C语言会先按操作数的类型(也就是int)来计算每一步:- 先算
n*n:2015671 * 2015671 = 4062929570241,这个数远大于32位int的最大值(约21亿),直接触发有符号整数溢出——这在C标准里属于未定义行为,但大多数编译器会按补码循环处理,得到一个错误的int值。 - 接着用这个错误的
int值再乘以n,结果还是错误的int值。 - 最后才把这个错误的
int转换成long long返回,自然和正确结果差十万八千里。
- 先算
而pow(n,3)能得到正确结果的原因是:
pow的参数是double类型,所以n会先被转换成double——32位int的所有值都能被double精确表示(因为double的尾数有52位+隐含位,能精确表示到2^53以内的整数,远大于32位int的最大值)。- 虽然
pow是浮点数运算,但对于这个特定的三次方计算,要么是你的编译器对整数幂做了优化(直接用整数运算实现),要么是这个立方值刚好落在double的精确表示范围内(不过严格来说,这个立方值已经超过2^53,理论上double无法精确表示,但可能刚好这个数的二进制形式能被double的尾数+指数组合精确存储,属于巧合)。
如何修正你的cube函数?
要避免中间运算溢出,只需要让中间步骤用long long类型计算就行,有两种常见方式:
- 把参数类型改成
long long:long long cube(long long n) { return n*n*n; } - 在计算前先把
n转换成long long:
注意这里只需要把第一个long long cube(int n) { return (long long)n * n * n; }n转成long long,后面的乘法会自动提升为long long类型,避免溢出。
内容的提问来源于stack exchange,提问作者nga1hte
相关产品推荐
相关产品推荐

