为什么我总是使用rand()得到相同的随机数序列?

时间:2009-07-10 10:18:02

标签: c random

这是我第一次用C语言尝试随机数(我想念C#)。这是我的代码:

int i, j = 0;
for(i = 0; i <= 10; i++) {
    j = rand();
    printf("j = %d\n", j);
}

使用此代码,每次运行代码时都会得到相同的序列。但是如果我在srand(/*somevalue/*)循环之前添加for,它会生成不同的随机序列。任何人都可以解释原因吗?

12 个答案:

答案 0 :(得分:81)

你必须播种它。随着时间播种它是一个好主意:

srand()

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main ()
{
  srand ( time(NULL) );
  printf ("Random Number: %d\n", rand() %100);
  return 0;
}

您获得了相同的序列,因为如果您不致电rand()srand()会自动播种,其值为1。

修改

由于评论

rand()将返回介于0和RAND_MAX之间的数字(在标准库中定义)。使用modulo运算符(%)会给出除法的余数rand() / 100。这将强制随机数在0-99范围内。例如,要获得0-999范围内的随机数,我们将应用rand() % 1000

答案 1 :(得分:33)

rand()返回pseudo-random个数字。它根据给定的算法生成数字。 该算法的起点始终相同,因此您将看到为每次调用生成的相同序列。当您需要验证程序的行为和一致性时,这很方便。

您可以使用 srand 函数设置随机生成器的“种子”(仅在程序中调用一次srand)从rand()生成器获取不同序列的一种常用方法是设置种子到当前时间或过程的ID:

程序开头的

srand(time(NULL)); srand(getpid());

为计算机生成真正的随机性非常困难,但对于实际的非加密相关工作,尝试均匀分布生成的序列的算法运行良好。

答案 2 :(得分:19)

引用man rand

  

srand()函数设置其参数   作为新序列的种子   要返回的伪随机整数   通过rand()。这些序列是   通过调用srand()可重复   相同的种子价值。

     

如果没有提供种子值,则   rand()函数是自动的   种子值为1。

因此,如果没有种子值,rand()会将种子假定为1(在您的情况下每次)并且具有相同的种子值,rand()将生成相同的数字序列。

答案 3 :(得分:11)

这里有很多答案,但是没有人似乎真的解释了为什么rand()总是在给定相同种子的情况下生成相同的序列 - 甚至是种子真的是什么这样做。所以这里。

rand()函数维护内部状态。从概念上讲,您可以将其视为某种类型的全局变量rand_state。每次调用rand()时,它都会执行两项操作。它使用现有状态来计算新状态,并使用新状态计算要返回给您的数字:

state_t rand_state = INITIAL_STATE;

state_t calculate_next_state(state_t s);
int calculate_return_value(state_t s);

int rand(void)
{
    rand_state = calculate_next_state(rand_state);
    return calculate_return_value(rand_state);
}

现在你可以看到每次调用rand()时,它都会使rand_state沿预定的路径向前移动一步。您看到的随机值仅基于您沿着该路径的位置,因此它们也将遵循预先确定的顺序。

现在这里是srand()的用武之地。它可以让你跳到路径上的另一个点:

state_t generate_random_state(unsigned int seed);

void srand(unsigned int seed)
{
    rand_state = generate_random_state(seed);
}

state_t,calculate_next_state(),calculate_return_value()和generate_random_state()的确切细节因平台而异,但它们通常很简单。

你可以从中看到,每次你的程序启动时,rand_state将从INITIAL_STATE开始(相当于generate_random_state(1)) - 这就是为什么你总是得到相同的序列,如果你不使用srand ()。

答案 4 :(得分:9)

如果我记得Knuth在随机数生成章节开头的开创性作品“计算机编程艺术”的引用,它就是这样的:

“从技术上讲,任何试图通过数学方法生成随机数的人都处于犯罪状态”。

简单地说,股票随机数生成器是算法,数学和100%可预测。在许多情况下这实际上是一件好事,其中需要可重复的“随机”数字序列 - 例如对于某些统计练习,您不希望结果中的“摆动”真正随机数据引入,这要归功于聚类效应。

虽然从计算机的硬件中抓取一些“随机”数据是一种流行的第二种选择,但它并不是真正随机的 - 尽管操作环境越复杂,随机性的可能性就越大 - 或者至少是不可预测性。

真正的随机数据生成器倾向于寻找外部资源。放射性衰变是最受欢迎的,类星体的行为也是如此。任何根源于量子效应的东西都是随机的 - 这对爱因斯坦的烦恼很大。

答案 5 :(得分:7)

随机数生成器实际上并不是随机数,它们像大多数软件一样是完全可预测的。 rand做的是每次调用一个看起来是随机的伪随机数。为了正确使用它,你需要给它一个不同的起点。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main ()
{
  /* initialize random seed: */
  srand ( time(NULL) );

  printf("random number %d\n",rand());
  printf("random number %d\n",rand());
  printf("random number %d\n",rand());
  printf("random number %d\n",rand());

  return 0;
}

答案 6 :(得分:2)

这是http://www.acm.uiuc.edu/webmonkeys/book/c_guide/2.13.html#rand

声明:

void srand(unsigned int seed); 

此函数为函数rand使用的随机数生成器播种。使用相同种子的种子srand将导致rand返回相同的伪随机数序列。如果没有调用srand,则rand就像调用srand(1)一样。

答案 7 :(得分:2)

rand()返回系列中的下一个(伪)随机数。发生的事情是每次运行时都有相同的系列(默认为“1”)。要为新系列播种,必须在开始调用rand()之前调用srand()。

如果您每次都想要随机的话,可以尝试:

srand (time (0));

答案 8 :(得分:1)

兰德不会为您提供随机数。它为您提供pseudorandom数字生成器生成的序列中的下一个数字。要在每次启动程序时获得不同的序列,必须通过调用srand来播种算法。

一种(非常糟糕的)方法是通过将当前时间传递给它:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main() {
    srand(time(NULL));
    int i, j = 0;
    for(i = 0; i <= 10; i++) {
        j = rand();
        printf("j = %d\n", j);
    }
    return 0;
}

为什么这是一个坏方法?因为伪随机数生成器与其种子一样好,并且种子必须不可预测。因此,您可能需要更好的熵源,例如从/dev/urandom中读取信息。

答案 9 :(得分:0)

在致电srand(sameSeed)之前致电rand()。更多详情here

答案 10 :(得分:0)

Seeding the rand()

void srand (unsigned int seed)
  

此函数将种子建立为新系列伪随机数的种子。如果在使用srand建立种子之前调用rand,则使用值1作为默认种子。

     

要在每次运行程序时生成不同的伪随机序列,请执行srand(time(0))

答案 11 :(得分:0)

你们没有人回答他的问题。

  

使用此代码我每次都获得相同的sequance但是如果我在for循环之前添加srand(/ somevalue /),它会生成随机序列。有谁可以解释为什么?

从我的教授告诉我的情况来看,如果你想确保你的代码正常运行并且看看是否有什么问题或者你是否可以改变某些东西,它就会被使用。