计算算术表达式时出现c++溢出
c++ overflow while calculating an arithmetic expression
#include <iostream>
int main(int argc, char* argv[]) {
std::cout << 30000 * (5 * 30000 - 22207) / 2 + 50488389 << std::endl;
return 0;
}
我想要的正确答案是1967383389,但这个程序在我的电脑上运行后输出了-180100259。它似乎已经溢出了。但为什么呢?如何判断算术表达式是否会溢出?
编译示例代码时,编译器通常会抛出一个警告,准确地识别表达式中溢出的部分
main.cpp:4:24: warning: integer overflow in expression [-Woverflow]
std::cout << 30000 * (5 * 30000 - 22207) / 2 + 50488389 << std::endl;
~~~~~~^~~~~~~~~~~~~~~~~~~~~
实时演示
为了克服这一点,使用所有浮点常数进行计算:
#include <iostream>
#include <cmath>
int main(int argc, char* argv[]) {
std::cout << std::trunc(30000.0 * (5.0 * 30000.0 - 22207.0) / 2.0 + 50488389.0) << std::endl;
// ^^ ^^ ^^ ^^ ^^ ^^
return 0;
}
实时演示
如何判断算术表达式是否会溢出?
您可以检查std::numeric_limits
以查看编译器实现和目标CPU可用的最大值。
如果你需要问题中提到的确切输出,你可以使用I/O操纵器将输出按形状:
std::cout << std::fixed << std::setprecision(0)
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
<< std::trunc(30000.0 * (5.0 * 30000.0 - 22207.0) / 2.0 + 50488389.0) << std::endl;
实时演示
要直接回答这个问题,溢出由类型的大小控制。常见的C++类型有int(32位(、long(64位(、float(32位的(和double(64位的(。根据平台的不同,类型的大小可能会有所不同,因此在处理大量数据时必须小心。例如,64位的int类型现在很常见,但在一些旧的嵌入式平台上可能是16位。
在您的案例中,一个中间值超过了sizeof(int(,它看起来是32位。结果将是垃圾。您可以使用浮点作为其他建议,但在某些情况下可能会导致一轮错误。
如果你坚持使用整数文字,你可以用一个尾随字母来分配类型吗。这里有很多细节:
http://en.cppreference.com/w/cpp/language/integer_literal
例如,我更喜欢使用我感兴趣的显式大小的变量int32_t或int64_t。
希望能帮上忙,
--Matt
它已经溢出,因为30000*(5*30000-22207(的计算结果为3833790000,大于int可以容纳的最大整数。算术表达式中的常量被视为int类型,对两个int类型进行算术运算将只产生int类型,因此发生溢出。
您可以通过在unix/linux中使用g++编译上述代码来检查包含常量的算术表达式是否会溢出。当像这样编译时,它会抛出一个警告-
警告:表达式[-Woverflow中存在整数溢出
要获得所需答案,您只需将30000*(5*30000-22207(中任何常数的类型转换为long类型,如long(30000(*(5*30000-22207(
溢出的原因如下:
30000 * (5 * 30000 - 22207) / 2 + 50488389
从左到右计算。计算结果
30000 * (5 * 30000 - 22207)
是
3833790000
相当于
-461177296
模2^32。这里发生溢出,因为您使用的是32位带符号的整数数据类型。
计算
-461177296 / 2 + 50488389
然后给你
-180100259
据我所知,您无法直接检测是否发生了溢出。一种可能的方法是在C++代码中插入一些汇编代码并检查溢出标志。(但你必须对编译器和你的系统有很好的了解,才能让它正常工作。(
- 'short int'持有的值溢出,但"自动"不会溢出?
- 使用动态分配的数组会导致代码分析发出虚假的C6386缓冲区溢出警告
- 大于65535的C++数组[size]引发不一致的溢出
- 为什么我在leetcode上收到AddressSanitizer:地址0x602000000058上的堆缓冲区溢出错误
- C++中无符号字符溢出
- 在 leetcode 上提交解决方案时出现堆栈缓冲区溢出错误
- 我的 int main() 中出现堆栈溢出错误
- 整数溢出,最大值为 pow(10,19)
- 获取隐式转换溢出从无符号到已签名的警告
- 使用 strcat 获取缓冲区溢出错误
- LeetCode 1:两和 - 地址清理器:堆缓冲区溢出地址
- 给定一个类型,如何派生一个泛型更广泛的类型(例如,用于溢出安全求和)?
- C++ 对象数组堆栈溢出
- 使用提升::lexical_cast捕获溢出
- C++ Unordered_set功能中的溢出
- 自定义排序函数中的堆溢出
- 使用向量的缓冲区溢出
- 有没有一种方法可以捕获进程中的堆栈溢出?C++Linux
- 如何修复此特征矩阵反演溢出错误?
- 自定义 std::fstream,std::filebuf 的溢出和下溢函数未为每个字符调用