C++ 学习笔记:整形数防止数据溢出
C/C++ 中的算术及其陷阱
https://www.cnblogs.com/kongj/p/14612362.html
数据溢出的处理方法,怎样防止数据溢出?
用 INT_MAX, 无法直接用 n > INT_MAX 来判断数据溢出,因为此时 n 已经溢出。
需要提前预判!
比如,a接近溢出,a * b 之后会大于INT_MAX的话,我们提前判断,
把a * b > INT_MAX 改为 a > INT_MAX / b
所以总结以下3点:
- 如果整数很容易超出(比如阶乘),程序需要有提前预判的措施
- int 的最大数值非常小,只有约20个亿左右!(2**31 - 1)
- 如果需要用到比较大的数,尽量用 int64_t (即 long long, 最大值2**63 - 1, 900亿亿左右),
- 如果是数组索引,可以用
std::size_t
, (如果是vector, deque之类的标准库容器,用vector<T>::size_type
类型的整数可以保证索引值覆盖容器大小)
典型例子是阶乘,整数很容易溢出,
- 13阶乘 > INT_MAX
- 21阶乘 > LLONG_MAX
需要预判防止溢出,
如以下代码,分别提供了 int 版本(32位)和 long long 版本(64位)
代码中的if (res > INT_MAX / i)
用于防止溢出。
(long long 版本的 INT_MAX 是 LLONG_MAX)
#include <iostream>
using namespace std;
/*
factorial, very likely to exceed in limit of int,
use INT_MAX to prevent this data overflow error.
*/
int factorial(int n) {
int res = 1;
for (int i = 1; i != (n + 1); ++i) {
if (res > INT_MAX / i) {
cerr << "\033[31;1m Error, data overflow. \033[0m" << endl;
return INT_MAX;
} else {
res *= i;
}
}
return res;
}
int64_t factorial_llong(int n) {
/// int64_t (= long long) version of int,
/// use LLONG_MAX instead of INT_MAX
int64_t res = 1;
for (int i = 1; i != (n + 1); ++i) {
if (res > LLONG_MAX / i) {
cerr << "\033[31;1m Error, data overflow. \033[0m" << endl;
return LLONG_MAX;
} else {
res *= i;
}
}
return res;
}
int main() {
/// LLONG_MAX is the long long version of INT_MAX
cout << "INT_MAX = " << INT_MAX << endl; // 2147483647 = 2**31 - 1
cout << "LONG_MAX = " << LONG_MAX << endl; // 2147483647 = 2**31 - 1
cout << "LLONG_MAX = " << LLONG_MAX << endl; // 9223372036854775807 = 2**63 - 1
auto a = 1;
while (1) {
cout << "a = ";
cin >> a;
cout << "got a = " << a << endl;
if (a == 0) break;
cout << "\033[35;1m factorial(a) = \033[0m" << factorial(a) << endl;
cout << "\033[35;1m factorial_llong(a) = \033[0m" << factorial_llong(a) << endl << endl;
}
return 0;
}
另外, mark一下,对于单双精度的浮点数,其能够表示的最大最小数值可以看这里https://blog.csdn.net/K346K346/article/details/50487127