我正在运行一个C ++程序,它在for循环中添加数字:
int y = 0;
for (int i=0; i<NUM; i++) {
int pow = 1;
for (int j=0 j<i; j++) {
pow *= 10;
}
y+= vec[i]*pow; // where vec is a vector of digits
}
但我不确定如何检查是否发生了溢出。有办法吗?
答案 0 :(得分:1)
有符号整数变量的溢出会导致未定义的行为。结果是,一旦发生溢出,就无法在标准C ++中可靠地检测到溢出。允许任何行为。因此,您的实现(编译器,库,工具集等)可能提供检测整数溢出的特定方法 - 但这意味着不一定适用于其他实现。
唯一的方法是在执行操作(或一系列操作)之前检查潜在的溢出。或者设计您的方法(例如选择限制)以防止发生溢出。
答案 1 :(得分:0)
有不同的选择,可能没有适合所有情况和需要的选择。
例如,在这种情况下,您可以在乘法之前检查pow
是否小于或等于INT_MAX/10
。这是有效的,因为INT_MAX/10
是最大的数字,因此它最多只有10 INT_MAX
。请注意,如果将INT_MAX/10
插入代码中,编译器通常会预先计算int y = 0;
for (int i=0; i<NUM; i++) {
int pow = 1;
for (int j=0 j<i; j++) {
if( pow > INT_MAX/10 )
throw OverflowException;
pow *= 10;
}
y+= vec[i]*pow; // where vec is a vector of digits
}
(否则,如果困扰您,可以将其放在局部变量中):
INT_MAX/n
这个解决方案的缺点是,如果另一个因素不是常数,编译器(和你)不能合理地避免在运行时完成除法int y = 0;
for (int i=0; i<NUM; i++) {
int32_t pow = 1;
for (int j=0 j<i; j++) {
int64_t tmp = (int64_t)pow * (int64_t)10;
if( tmp > (int64_t)INT32_MAX )
raise OverflowException;
pow = (int32_t)tmp;
}
y+= vec[i]*pow; // where vec is a vector of digits
}
(并且除法通常比乘法更昂贵)。
另一种可能性是你可以用更广泛的类型进行计算。例如:
# reviewer
has_one :reviewer
accepts_nested_attributes_for :reviewer
has_many :active_managements, class_name: 'Reviewer',
foreign_key: 'reviewer_id',
dependent: :destroy
has_one :my_reviewer, through: :reviewer, source: :user
这样做的缺点是,首先可能无法使用更宽的类型,如果是,则可能需要软件实现乘法(例如32位系统上的64位),这意味着乘法速度较慢。
另一种情况是你添加两个整数。如果发生溢出,结果将小于两个整数,特别是如果它们都是正数,则结果将是负数。
答案 2 :(得分:0)
正如彼得正确的explained,标准 C ++ 11(或C99)中的溢出是undefined behavior ,你真的应该{ {3}}
但是,有些编译器会为您提供扩展来处理和检测整数溢出。
如果您可以将自己限制在最近的afraid of UB编译器中,则可以使用其GCC。
您还可以将自己限制为int32_t
并在int64_t
中计算算术,并检查INT32_MAX
或INT32_MIN
以上的结果。这可能比使用编译器特定的扩展更慢(但更便携)。 BTW一些编译器也有一些__int128_t
类型(因此您可以在__int128_t
中计算算术并同样检查结果是否适合int64_t
)。
如果你的目标是拥有integer overflow builtins,最好使用一些现有的bignum库,例如arbitrary precision arithmetic(因为高效的 bignum算法需要非常聪明的算法)。