使用gcc c99进行编译,而不是使用ideone c99进行编译。整数溢出

时间:2011-10-11 03:04:10

标签: c c99

int rng(int min, int max){
    int result = min + ( ( (max - (min - 1) ) * rand() ) / (RAND_MAX + 1) );
    return result;
}

这不会使用c99模式使用ideone进行编译,但是当我在-std=c99上使用代码块上的gcc时会这样做。我认为使用long int会做到这一点,但显然不是这样。当我在学校尝试一些东西时,我使用了ideone,因为他们只有VC ++,我正在做C C99。我不想在我需要的时候使用这个功能,所以在这里我要问的是什么是错的。

4 个答案:

答案 0 :(得分:2)

实际上,在我的编译器上生成warning: integer overflow in expression [-Woverflow]

问题是由RAND_MAX + 1引起的。 RAND_MAX经常与INT_MAX相同。将1添加到INT_MAX当然会产生未定义的行为(除了编译器在编译时捕获并用其他东西替换代码)。

如果你想看看它为什么不好,请这样做:

scanf("%d", &dummy); /* So the compiler won't catch it. */
dummy += INT_MAX;

gcc -ftrapv -Wall -Wextra # ftrapv is the key point

答案 1 :(得分:2)

在ideone中查看。

#include <stdlib.h>
#include <stdio.h>
int main(void) { printf("%x\n", RAND_MAX); return 0; }

您会注意到它会打印7fffffff,这可能也是MAX_INT。计算MAX_INT + 1时会发生什么?无论您是否收到错误,计算MAX_INT + 1都是错误的。

在给定具有不同范围的统一RNG的情况下,有许多方法可以编写均匀随机数生成器,但正确执行此操作有点棘手。

这应该适用于max - min <= RAND_MAXmax > min ...

int rng(int min, int max)
{
    int range = max - min + 1;
    int factor = ((unsigned) RAND_MAX + 1) / range;
    int x;
    do {
        x = rand() / factor;
    } while (x >= range);
    return x + min;
}

这应该是统一的并且提供相对高质量的数字(已知使用%会导致某些PRNG和某些范围出现严重的质量问题。)

答案 2 :(得分:1)

没有实际的错误文本,很难分辨,但标题中存在“整数溢出”指向......,整数溢出: - )

如果RAND_MAX +1实际上与RAND_MAX相同,那么最有可能是INT_MAX位的罪魁祸首。

如果您愿意放弃随机数(a)完美分发,您可以选择以下内容:

int rng (int minVal, int maxVal) {
    int result = min + (rand() % (maxVal + 1 - minVal));
    return result;
}

(a)由此造成的“损害”通常是最小的,但 稍微偏离了最高值的分布。如果这很重要,除了统计学家之外,还有其他方法可以接受。

答案 3 :(得分:0)

如果(max - min + 1) * RAND_MAX > INT_MAX,这确实可以产生整数溢出。关于如何避免这种情况,你有几个选择:

  • 将中间值强制转换为可以存储它们而不会溢出的类型,例如uint64_tdouble
  • 使用模数运算符%,如下所示:
int rng ( int min, int max ) {
    return min + rand() % (max - min + 1);
}

请注意,使用%有一些缺点:如果max - min + 1不是2的幂,它会略微将结果偏向范围的低端(因为它不会除RAND_MAX+1 1}}均匀);如果 是2的幂,它可能会减少随机数流的周期和质量(因为LCRNG的低位比高位更不随机)。< / p>

有些方法可以通过仔细编码来避免这些问题。有关示例,请参阅Java中的标准Random.nextInt()实现,该实现可以非常直接地转换为C:

int rng (int min, int max) {
    int n = max - min + 1;
    int bits, val;

    if ((n & -n) == n)  // i.e., n is a power of 2
        return min + (int)((n * (uint64_t)rand()) / ((uint64_t)RAND_MAX + 1));

    do {
        bits = rand();
        val = bits % n;
    } while(bits - val > RAND_MAX - (n-1));

    return min + val;
}

(我认为这个翻译应该按照预期的方式工作。事实证明它比我更棘手,因为原始的Java代码实际上依赖INT_MAX = RAND_MAX = (1<<31)-1的假设,这可能不适用于C。)