我用c++写了一个程序来寻找ab = C的所有解,其中a, b和C一起使用所有的数字0-9,只使用一次。程序循环遍历a和b的值,并每次对a、b和ab运行数字计数例程,以检查是否满足数字条件。

但是,当ab超出整数限制时,会产生伪解。我最终使用如下代码来检查这个:

unsigned long b, c, c_test;
...
c_test=c*b;         // Possible overflow
if (c_test/b != c) {/* There has been an overflow*/}
else c=c_test;      // No overflow

是否有更好的方法来测试溢出?我知道有些芯片有一个内部标志,在溢出发生时设置,但我从未见过通过C或c++访问它。


注意,有符号int溢出在C和c++中是未定义的行为,因此您必须在不实际引起它的情况下检测它。对于加法前的有符号整型溢出,请参见在C/ c++中检测有符号溢出。


当前回答

salter先生的回答是个好主意。

如果整数计算是必需的(为了精度),但浮点数是可用的,你可以这样做:

uint64_t foo(uint64_t a, uint64_t b) {
    double dc;

    dc = pow(a, b);

    if (dc < UINT_MAX) {
       return (powu64(a, b));
    }
    else {
      // Overflow
    }
}

其他回答

我需要为浮点数回答同样的问题,在浮点数中位屏蔽和移位看起来没有希望。我确定的方法适用于有符号和无符号,整数和浮点数。即使没有更大的数据类型可以用于中间计算,它也可以工作。对于所有这些类型,它不是最有效的,但因为它确实适用于所有类型,所以值得使用。

有符号溢出测试,加减法:

Obtain the constants that represent the largest and smallest possible values for the type, MAXVALUE and MINVALUE. Compute and compare the signs of the operands. a. If either value is zero, then neither addition nor subtraction can overflow. Skip remaining tests. b. If the signs are opposite, then addition cannot overflow. Skip remaining tests. c. If the signs are the same, then subtraction cannot overflow. Skip remaining tests. Test for positive overflow of MAXVALUE. a. If both signs are positive and MAXVALUE - A < B, then addition will overflow. b. If the sign of B is negative and MAXVALUE - A < -B, then subtraction will overflow. Test for negative overflow of MINVALUE. a. If both signs are negative and MINVALUE - A > B, then addition will overflow. b. If the sign of A is negative and MINVALUE - A > B, then subtraction will overflow. Otherwise, no overflow.

签名溢出测试,乘法和除法:

Obtain the constants that represent the largest and smallest possible values for the type, MAXVALUE and MINVALUE. Compute and compare the magnitudes (absolute values) of the operands to one. (Below, assume A and B are these magnitudes, not the signed originals.) a. If either value is zero, multiplication cannot overflow, and division will yield zero or an infinity. b. If either value is one, multiplication and division cannot overflow. c. If the magnitude of one operand is below one and of the other is greater than one, multiplication cannot overflow. d. If the magnitudes are both less than one, division cannot overflow. Test for positive overflow of MAXVALUE. a. If both operands are greater than one and MAXVALUE / A < B, then multiplication will overflow. b. If B is less than one and MAXVALUE * B < A, then division will overflow. Otherwise, no overflow.

注意:MINVALUE的最小溢出由3处理,因为我们取的是绝对值。然而,如果 ABS(MINVALUE) > MAXVALUE,那么我们将会有一些罕见的假阳性。

下溢测试类似,但涉及EPSILON(大于零的最小正数)。

不能从C/ c++中访问溢出标志。

有些编译器允许你在代码中插入陷阱指令。在GCC上,选项是-ftrapv。

唯一可移植且与编译器无关的事情是自己检查溢出。就像你的例子一样。

但是,使用最新的GCC, -ftrapv似乎在x86上什么都不做。我猜这是一个旧版本的残余,或者特定于其他一些架构。我曾期望编译器在每次添加后插入一个INTO操作码。不幸的是,它不能这样做。

一种简单的方法是重写所有操作符(特别是+和*),并在执行操作之前检查是否有溢出。

我看到你用的是无符号整数。根据定义,在C中(我不了解c++),无符号算术不会溢出…所以,至少对C来说,你的观点是没有意义的:)

对于有符号整数,一旦出现溢出,就会发生未定义行为(UB),程序可以做任何事情(例如:使测试不确定)。

#include <limits.h>

int a = <something>;
int x = <something>;
a += x;              /* UB */
if (a < 0) {         /* Unreliable test */
  /* ... */
}

要创建一个符合要求的程序,您需要在生成溢出之前测试溢出。该方法也可以用于无符号整数:

// For addition
#include <limits.h>

int a = <something>;
int x = <something>;
if (x > 0 && a > INT_MAX - x) // `a + x` would overflow
if (x < 0 && a < INT_MIN - x) // `a + x` would underflow

// For subtraction
#include <limits.h>
int a = <something>;
int x = <something>;
if (x < 0 && a > INT_MAX + x) // `a - x` would overflow
if (x > 0 && a < INT_MIN + x) // `a - x` would underflow

// For multiplication
#include <limits.h>

int a = <something>;
int x = <something>;
// There may be a need to check for -1 for two's complement machines.
// If one number is -1 and another is INT_MIN, multiplying them we get abs(INT_MIN) which is 1 higher than INT_MAX
if (a == -1 && x == INT_MIN) // `a * x` can overflow
if (x == -1 && a == INT_MIN) // `a * x` (or `a / x`) can overflow
// general case
if (x != 0 && a > INT_MAX / x) // `a * x` would overflow
if (x != 0 && a < INT_MIN / x) // `a * x` would underflow

对于除法(INT_MIN和-1特殊情况除外),不可能超过INT_MIN或INT_MAX。

mozilla::CheckedInt<T>为整数类型T提供溢出检查的整数数学(使用clang和gcc上可用的编译器intrinsic)。该代码是在MPL 2.0下编写的,并且依赖于三个(integertypetrait .h, Attributes.h和Compiler.h)其他仅针对标头的非标准库标头以及mozilla特定的断言机制。如果导入代码,可能需要替换断言机制。