如何在C++中避免整数溢出和下溢
在C++中,整数分配了一定数量的位。如果一个整数值占用比分配的位数更多的位,则可能会遇到溢出或下溢。
- 整数溢出 发生在数字大于数据类型可以容纳的最大值时。
- 整数下溢 发生在数字小于数据类型可以容纳的最小值时。
我们在C++中主要处理这些数据类型以存储整数。它们是:
- signed int: 有符号int数据类型的范围为 -2,147,483,648 至 2,147,483,647 (-10的9次方到10的9次方)。
- unsigned int: 无符号int数据类型的范围为 0 至 4,294,967,295 。
- long long: long long数据类型的范围为 -9,223,372,036,854,775,808 至 9,223,372,036,854,775,807 (-10的18次方到10的18次方)。
接下来让我们详细讨论整数溢出和下溢。
整数溢出
示例: 在下面的C++程序中,三个变量a、b和c被初始化为有符号的int数据类型:
// C++ program to demonstrate
// integer overflow
#include <iostream>
using namespace std;
// Driver code
int main()
{
int a = 100000;
int b = 100000;
int c = a * b;
cout << "The product of a and b is " <<
c << endl;
return 0;
}
输出
The product of a and b is 1410065408
时间复杂度: O(1)
辅助空间: O(1)
解释: c的预期值为10的10次方,但输出值是1410065408。这是因为整数c最多能存储10的9次方的范围。
解决方案1:
1. 将变量c初始化为long long数据类型。
long long c = a * b;
2.问题仍然存在,因为a和b都是int数据类型,而两个int数据类型的乘积始终是一个介于int范围内的整数。
3.将a或b初始化为long long数据类型。由于int和long long的乘积是long long。 因此,a和b将产生一个long long范围。
以下是实现上述解决方案以处理整数溢出的C++程序:
// C++ program to handle integer
// overflow
#include <iostream>
using namespace std;
// Driver code
int main()
{
int a = 100000;
// Changed int b to long long b
long long b = 100000;
long long c = a * b;
cout << "The product of a and b is " <<
c << endl;
return 0;
}
输出
a和b的积为10000000000
解决方案2:
1. 将变量 c 初始化为 long long 数据类型。
long long c = a * b;
2. 在初始化 c 的值时,我们可以将 a 和 b 与 1LL 相乘,而不是更改它们的数据类型,这样,即使使用 long long 1 与 a 和 b 相乘,也会得到 long long 并将其存储在变量 c 中。
以下是实现上述解决方法以处理整数溢出的C++代码:
// C++ program to handle integer
// overflow
#include <iostream>
using namespace std;
// Driver code
int main()
{
int a = 100000;
int b = 100000;
// Here we multiplied 'a' with 1LL
// which results into long long
// which is further multiplied with 'b'
long long c = a * 1LL * b;
cout << "The product of a and b is " <<
c << endl;
return 0;
}
输出
a和b的积为10000000000
解决方案3:
将变量a、b和c最初都初始化为 long long 数据类型。这将使我们获得所需的输出,但需要一些额外的内存空间。
以下是实现上述解决方法以处理整数溢出的C++代码:
// C++ program to handle integer
// overflow
#include <iostream>
using namespace std;
// Driver code
int main()
{
// Here we changed the data types
// of both a and b to long long
// to avoid overflow
long long a = 100000, b = 100000;
long long c = a * b;
cout << "The product of a and b is " <<
c << endl;
return 0;
}
输出
a和b的积为10000000000
整数下溢
例子1: 在下面的代码中,将3个变量 a 、 b 和 c 初始化为无符号整数类型,以显示整数下溢:
// C++ program to show integer
// underflow
#include <iostream>
using namespace std;
// Driver code
int main()
{
unsigned int a = 4, b = 5;
unsigned int c = a - b;
cout << c;
return 0;
}
输出
4294967295
解释:
变量 c 的期望值为 -1 ,但输出为 4294967295 。这是因为 unsigned int c 无法存储负值。
解决方案1:
为了解决上述问题,可以将变量 c 初始化为 int(signed) 类型以存储负数。以下是显示如何处理整数下溢的C++代码:
// C++ program to show how to
// handle integer underflow
#include <iostream>
using namespace std;
// Driver code
int main()
{
unsigned int a = 4, b = 5;
// Here we changed data type of
// c to signed int
int c = a - b;
cout << c;
return 0;
}
输出
-1
示例2: 在下面的代码中,变量 a 被初始化为无符号整数,变量 b 和 c 被初始化为整数,以显示整数下溢:
// C++程序演示整数下溢
#include <iostream>
using namespace std;
// 驱动程序
int main()
{
unsigned int a = 1000000;
int b = -10000;
int c = b * a;
cout << c;
return 0;
}
输出结果
-1410065408
解释:
变量 c 的期望值是 -10 10,但实际输出值是 -1410065408 。这是由于有符号整数 c 不能储存小于 -2,147,483,648 的负数值。
解决方案1:
1. 将变量 c 初始化为 long long 数据类型,以存储 -10 10。
long long c = b * a;
2. 但是,问题仍存在,因为变量 a 是无符号整数而变量 b 是有符号整数,因此它们的乘积不能是 long long 范围内的任何数字。因此,我们需要将它们中的一个更改为 long long 数据类型。
// C++程序处理整数下溢
#include <iostream>
using namespace std;
// 驱动程序
int main()
{
unsigned int a = 1000000;
long long b = -10000;
long long c = b * a;
cout << c;
return 0;
}
输出结果
-10000000000
解决方案2:
无需更改变量 a 和 b 的数据类型,我们可以在初始化变量 c 的值时将 a 和 b 与 1LL 相乘,这样, a 和 b 乘以长整型1的结果也将变成长整型,并且该值将储存在 long long c .
// C++程序处理整数下溢
#include <iostream>
using namespace std;
// 驱动程序
int main()
{
unsigned int a = 1000000;
int b = -10000;
long long c = b * 1LL * a;
cout << c;
return 0;
}
输出结果
-10000000000