我用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++中检测有符号溢出。


当前回答

尝试这个宏来测试32位机器的溢出位(改编自Angel Sinigersky的解决方案)

#define overflowflag(isOverflow){   \
size_t eflags;                      \
asm ("pushfl ;"                     \
     "pop %%eax"                    \
    : "=a" (eflags));               \
isOverflow = (eflags >> 11) & 1;}

我将其定义为宏,因为否则溢出位将被覆盖。

下面是上面代码段的一个小应用程序:

#include <cstddef>
#include <stdio.h>
#include <iostream>
#include <conio.h>
#if defined( _MSC_VER )
#include <intrin.h>
#include <oskit/x86>
#endif

using namespace std;

#define detectOverflow(isOverflow){     \
size_t eflags;                      \
asm ("pushfl ;"                     \
    "pop %%eax"                     \
    : "=a" (eflags));               \
isOverflow = (eflags >> 11) & 1;}

int main(int argc, char **argv) {

    bool endTest = false;
    bool isOverflow;

    do {
        cout << "Enter two intergers" << endl;
        int x = 0;
        int y = 0;
        cin.clear();
        cin >> x >> y;
        int z = x * y;
        detectOverflow(isOverflow)
        printf("\nThe result is: %d", z);
        if (!isOverflow) {
            std::cout << ": no overflow occured\n" << std::endl;
        } else {
            std::cout << ": overflow occured\n" << std::endl;
        }

        z = x * x * y;
        detectOverflow(isOverflow)
        printf("\nThe result is: %d", z);
        if (!isOverflow) {
            std::cout << ": no overflow ocurred\n" << std::endl;
        } else {
            std::cout << ": overflow occured\n" << std::endl;
        }

        cout << "Do you want to stop? (Enter \"y\" or \"Y)" << endl;

        char c = 0;

        do {
            c = getchar();
        } while ((c == '\n') && (c != EOF));

        if (c == 'y' || c == 'Y') {
            endTest = true;
        }

        do {
            c = getchar();
        } while ((c != '\n') && (c != EOF));

    } while (!endTest);
}

其他回答

测试溢出的简单方法是通过检查当前值是否小于前一个值来进行验证。例如,假设你有一个循环输出2的幂:

long lng;
int n;
for (n = 0; n < 34; ++n)
{
   lng = pow (2, n);
   printf ("%li\n", lng);
}

添加溢出检查的方式,我描述的结果如下:

long signed lng, lng_prev = 0;
int n;
for (n = 0; n < 34; ++n)
{
    lng = pow (2, n);
    if (lng <= lng_prev)
    {
        printf ("Overflow: %i\n", n);
        /* Do whatever you do in the event of overflow.  */
    }
    printf ("%li\n", lng);
    lng_prev = lng;
}

它既适用于无符号值,也适用于正负符号值。

当然,如果您想对递减值而不是递增值执行类似的操作,您可以将<=符号翻转,使其为>=,假设下溢的行为与溢出的行为相同。坦率地说,这是在不访问CPU溢出标志的情况下所获得的可移植性(这将需要内联汇编代码,使您的代码在实现之间无法移植)。

I see that a lot of people answered the question about overflow, but I wanted to address his original problem. He said the problem was to find ab=c such that all digits are used without repeating. Ok, that's not what he asked in this post, but I'm still think that it was necessary to study the upper bound of the problem and conclude that he would never need to calculate or detect an overflow (note: I'm not proficient in math so I did this step by step, but the end result was so simple that this might have a simple formula).

重点是问题要求的a b c的上限是98.765.432。不管怎样,先把问题分成琐碎部分和非琐碎部分:

X0 == 1(9、8、7、6、5、4、3、2的所有排列都是解) X1 == x(无解) 0b == 0(不可能解) 1b == 1(无解) Ab, a > 1, b > 1(非平凡)

Now we just need to show that no other solution is possible and only the permutations are valid (and then the code to print them is trivial). We go back to the upper bound. Actually the upper bound is c ≤ 98.765.432. It's the upper bound because it's the largest number with 8 digits (10 digits total minus 1 for each a and b). This upper bound is only for c because the bounds for a and b must be much lower because of the exponential growth, as we can calculate, varying b from 2 to the upper bound:

    9938.08^2 == 98765432
    462.241^3 == 98765432
    99.6899^4 == 98765432
    39.7119^5 == 98765432
    21.4998^6 == 98765432
    13.8703^7 == 98765432
    9.98448^8 == 98765432
    7.73196^9 == 98765432
    6.30174^10 == 98765432
    5.33068^11 == 98765432
    4.63679^12 == 98765432
    4.12069^13 == 98765432
    3.72429^14 == 98765432
    3.41172^15 == 98765432
    3.15982^16 == 98765432
    2.95305^17 == 98765432
    2.78064^18 == 98765432
    2.63493^19 == 98765432
    2.51033^20 == 98765432
    2.40268^21 == 98765432
    2.30883^22 == 98765432
    2.22634^23 == 98765432
    2.15332^24 == 98765432
    2.08826^25 == 98765432
    2.02995^26 == 98765432
    1.97741^27 == 98765432

注意,例如最后一行:它说1.97^27 ~98M。因此,例如,1^27 == 1和2^27 == 134.217.728,这不是一个解决方案,因为它有9位数字(2 > 1.97,所以它实际上比应该测试的要大)。可以看到,用于测试a和b的组合非常小。对于b == 14,我们需要尝试2和3。对于b == 3,我们从2开始,到462结束。结果均小于~98M。

现在只需测试以上所有的组合,找出不重复任何数字的组合:

    ['0', '2', '4', '5', '6', '7', '8'] 84^2 = 7056
    ['1', '2', '3', '4', '5', '8', '9'] 59^2 = 3481
    ['0', '1', '2', '3', '4', '5', '8', '9'] 59^2 = 3481 (+leading zero)
    ['1', '2', '3', '5', '8'] 8^3 = 512
    ['0', '1', '2', '3', '5', '8'] 8^3 = 512 (+leading zero)
    ['1', '2', '4', '6'] 4^2 = 16
    ['0', '1', '2', '4', '6'] 4^2 = 16 (+leading zero)
    ['1', '2', '4', '6'] 2^4 = 16
    ['0', '1', '2', '4', '6'] 2^4 = 16 (+leading zero)
    ['1', '2', '8', '9'] 9^2 = 81
    ['0', '1', '2', '8', '9'] 9^2 = 81 (+leading zero)
    ['1', '3', '4', '8'] 3^4 = 81
    ['0', '1', '3', '4', '8'] 3^4 = 81 (+leading zero)
    ['2', '3', '6', '7', '9'] 3^6 = 729
    ['0', '2', '3', '6', '7', '9'] 3^6 = 729 (+leading zero)
    ['2', '3', '8'] 2^3 = 8
    ['0', '2', '3', '8'] 2^3 = 8 (+leading zero)
    ['2', '3', '9'] 3^2 = 9
    ['0', '2', '3', '9'] 3^2 = 9 (+leading zero)
    ['2', '4', '6', '8'] 8^2 = 64
    ['0', '2', '4', '6', '8'] 8^2 = 64 (+leading zero)
    ['2', '4', '7', '9'] 7^2 = 49
    ['0', '2', '4', '7', '9'] 7^2 = 49 (+leading zero)

没有一个匹配问题(这也可以通过缺少'0','1',…“9”)。

下面是解决该问题的示例代码。还要注意,这是用Python编写的,不是因为它需要任意精确整数(代码不会计算任何大于9800万的数字),而是因为我们发现测试的数量非常少,所以我们应该使用高级语言来利用其内置的容器和库(还要注意:代码有28行)。

    import math

    m = 98765432
    l = []
    for i in xrange(2, 98765432):
        inv = 1.0/i
        r = m**inv
        if (r < 2.0): break
        top = int(math.floor(r))
        assert(top <= m)

        for j in xrange(2, top+1):
            s = str(i) + str(j) + str(j**i)
            l.append((sorted(s), i, j, j**i))
            assert(j**i <= m)

    l.sort()
    for s, i, j, ji in l:
        assert(ji <= m)
        ss = sorted(set(s))
        if s == ss:
            print '%s %d^%d = %d' % (s, i, j, ji)

        # Try with non significant zero somewhere
        s = ['0'] + s
        ss = sorted(set(s))
        if s == ss:
            print '%s %d^%d = %d (+leading zero)' % (s, i, j, ji)

内联程序集允许您直接检查溢出位。如果你打算使用c++,你真的应该学习汇编。

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

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

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(大于零的最小正数)。

用double计算结果。它们有15位有效数字。您的要求在c上有一个硬上限108 -它最多可以有8位数字。因此,如果它在范围内,结果将是精确的,否则它将不会溢出。