假设我要加1 + 11 + 111 ....加n次。 显然,从证明素值n开始,累积总和可能会溢出。
假设我使用以下非常简单的函数来计算上述总和:
int calcSum(int num)
{
int sum = 0, sequnt = 1, i;
for (i = 0; i < num; i++)
{
sum += sequnt;
sequnt = (sequnt * 10) + 1;
}
return sum;
}
对于该功能,我想添加一个检查溢出的地方。
我试图在这里How to check if a number overflows an 'int'
寻求帮助。但是我不得不承认它使我感到困惑,并且在执行任务中仍然遇到一些困难。
任何帮助都会得到补偿。
答案 0 :(得分:3)
只需使用INT_MAX
中的limits.h
int calcSum(int num)
{
int sum = 0, sequnt = 1, i;
for (i = 0; i < num; i++)
{
if (INT_MAX - sequnt < sum) exit(1); // overflow
sum += sequnt;
if (INT_MAX/10 <= sequnt) exit(1); // overflow on the two next sentences.
sequnt *= 10;
sequnt++;
}
return sum;
}
exit(1)
仅是为了使示例简短。您可以添加所需的任何错误处理。
答案 1 :(得分:3)
由于2个加法或乘法中的任意一个都是溢出候选,因此请为每个安全调用overflow checker。在<limits.h>
中使用常量来指导范围检查。
#include <limits.h>
int is_undefined_add(int a, int b) {
return (a < 0) ? (b < INT_MIN - a) : (b > INT_MAX - a);
}
int is_undefined_mult(int a, int b) {
if (a > 0) {
if (b > 0) {
return a > INT_MAX / b; // a positive, b positive
}
return b < INT_MIN / a; // a positive, b not positive
}
if (b > 0) {
return a < INT_MIN / b; // a not positive, b positive
}
return a != 0 && b < INT_MAX / a; // a not positive, b not positive
}
int calcSum(int num) {
int sum = 0, sequnt = 1, i;
for (i = 0; i < num; i++) {
if (is_undefined_add(sum, sequnt) Handle_Overflow();
sum += sequnt;
if (is_undefined_mult(sequnt, 10) Handle_Overflow();
sequnt *= 10;
if (is_undefined_add(sequnt, 1) Handle_Overflow();
sequnt++;
}
return sum;
}
is_undefined_add()
和is_undefined_mult()
对int a, int b
的所有组合均有效。
答案 2 :(得分:1)
如果您确定使用的是二进制补码整数,则可以检查以下内容:添加的两个正数必须给出一个正结果,而添加的两个负数必须给出一个负结果。 两次溢出是不可能的,因此,如果您添加正数,则当您的结果首次为负数时就会出现溢出。
无论哪种情况,如果您都希望代码具有可移植性,那么建议您执行类似以下操作:
#include <limits.h>
...
if ((a > 0 && b > 0 && MAX_INT - a > b) ||
(a < 0 && b < 0 && MIN_INT - a < b)) {
/* OVERFLOW OF a + b WILL OCCUR */
...
}
如果操作数的符号不同,则a + b
的绝对值不可能大于a
或b
,因此不可能发生溢出。
对于unsigned
,您可以采用类似的方法(节省一半的测试时间,因为操作数只能是正数),但是这一次第一种方法始终有效(因为标准表示无符号加法被认为是总和模块2^n
,其中n
是按字表示的大小,在这种情况下,您可以求和,然后检查结果是否小于任何操作数(如果两个都为正,则求和必须更大)等于或等于任何操作数):
unsigned a, b;
...
unsigned sum = a + b;
if (sum < a || sum < b) {
/* OVERFLOW ON a + b HAS HAPPENED */
...
}
您还必须检查整数乘法溢出。如果a
和b
要相乘,则a*b
可能溢出。但是这一次问题更加严重了,因为溢出可能发生不止一次,并且您不能后验。在这种情况下,您可能会用相同或不同符号的溢出,因为如果两个符号相等,则您将a
与b
乘以b
(并且if (MAX_INT/b < a) { /* overflow */ }
与它本身具有相同的符号)为正,将发生溢出
if (MIN_INT/b < a) { /* overflow */ }
如果符号不同,则乘积应为负,然后
open layer
如果数字之一为0,则乘法时不会发生溢出,结果为0。