我想找到一种在C中获取随机数的无法解释的方法(尽管最多我会将其用于0-20的值,更可能只有0-8)。我已经看过这个公式,但经过一些测试后,我不确定它是否有偏差。有什么帮助吗?
以下是使用的完整功能:
int randNum()
{
return 1 + (int) (10.0 * (rand() / (RAND_MAX + 1.0)));
}
我用它来播种:
unsigned int iseed = (unsigned int)time(NULL);
srand (iseed);
下面提出的建议拒绝为我工作
int greek;
for (j=0; j<50000; j++)
{
greek =rand_lim(5);
printf("%d, " greek);
greek =(int) (NUM * (rand() / (RAND_MAX + 1.0)));
int togo=number[greek];
number[greek]=togo+1;
}
它停止工作,当我注释掉printf时,给我相同的数字50000次。
答案 0 :(得分:16)
是的,它是倾斜的,除非您的RAND_MAX恰好是10的倍数。
如果您将数字从0到RAND_MAX,并尝试将它们分成10堆,那么您实际上只有三种可能性:
你很少能控制RAND_MAX,而且无论如何它通常都是素数。这真的只剩下2和3作为可能性。
第三个选项大致如下: [编辑:经过一番思考,我修改了这个以生成0 ...(limit-1)范围内的数字,以适应C和C ++中大多数事情的工作方式。这也简化了代码(一点点)。
int rand_lim(int limit) {
/* return a random number in the range [0..limit)
*/
int divisor = RAND_MAX/limit;
int retval;
do {
retval = rand() / divisor;
} while (retval == limit);
return retval;
}
对于任何质疑这种方法是否会留下一些偏差的人,我也写了一个相当不同的版本,纯粹是为了测试。这个使用非常随机的发生器,其范围非常有限,因此我们可以简单地遍历范围内的每个数字。它看起来像这样:
#include <stdlib.h>
#include <stdio.h>
#define MAX 1009
int next_val() {
// just return consecutive numbers
static int v=0;
return v++;
}
int lim(int limit) {
int divisor = MAX/limit;
int retval;
do {
retval = next_val() / divisor;
} while (retval == limit);
return retval;
}
#define LIMIT 10
int main() {
// we'll allocate extra space at the end of the array:
int buckets[LIMIT+2] = {0};
int i;
for (i=0; i<MAX; i++)
++buckets[lim(LIMIT)];
// and print one beyond what *should* be generated
for (i=0; i<LIMIT+1; i++)
printf("%2d: %d\n", i, buckets[i]);
}
所以,我们从0到1009的数字开始(1009是素数,因此它不会是我们选择的任何范围的精确倍数)。所以,我们从1009个数字开始,然后将它分成10个桶。这应该在每个桶中提供100个,并且9个剩余物(可以这么说)被do
/ while
循环“吃掉”。正如它现在所写,它分配并打印出一个额外的桶。当我运行它时,我在桶0中的每个桶中得到100个,在桶10中得到0。如果我注释掉do
/ while
循环,我会在0中看到100。桶9中的.9和9。
为了确保,我已经使用各种其他数字重新运行测试,包括产生的范围(主要使用的素数)和桶的数量。到目前为止,我无法让它产生任何范围的偏差结果(当然,只要启用do
/ while
循环)。
另一个细节:我在这个算法中使用除法而不是余数是有原因的。有了rand()
的良好(甚至是不错的)实现它是无关紧要的,但当你使用除法将数字钳位到一个范围时,你保留了上位输入。使用余数执行此操作时,保留输入的较低位。实际上,对于典型的线性同余伪随机数发生器,较低位往往比高位更不随机。一个合理的实现将抛出一些最不重要的位,使这无关紧要。另一方面,rand
周围存在一些非常差的实现,并且使用大多数,通过使用除法而不是余数,最终得到更好的输出质量。
我还应该指出是生成器大致相反 - 低位比高位更随机。至少根据我的经验,这些都是非常罕见的。高位更随机的是相当更常见。