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。我不想不在我需要的时候使用这个功能,所以在这里我要问的是什么是错的。
答案 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_MAX
和max > 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_t
或double
或%
,如下所示: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。)