2011-09-08 99 views

回答

86

这取决于你想达到的目标。

随机化作为具有起始值,即种子的函数来执行。

因此,对于相同的种子,您将始终获得相同的值序列。

如果尝试每次你需要一个随机值时设置种子和种子是相同的号码,你总是会得到相同的“随机”值。

种子通常取自当前时间,即秒数,因为在time(NULL)中,所以如果您始终在采用随机数之前设置种子,只要调用srand/rand,就会得到相同的数字在同一秒内组合多次

为了避免这个问题,每个应用程序只设置一次srand,因为两个应用程序实例在同一秒内运行是有疑问的,所以每个实例都会有不同的随机数序列。

然而,你会在短时间内多次运行你的应用程序(特别是如果它是一个简短的,或命令行工具或类似的东西),那么你将不得不求助于其他应用程序选择种子的方法(除非你在不同的应用程序实例中的相同序列是可以的)。但正如我所说,这取决于您的应用程序使用情况。

此外,你可能想尝试,以增加精度微秒(减少同一种子的机会),要求(sys/time.h):

struct timeval t1; 
gettimeofday(&t1, NULL); 
srand(t1.tv_usec * t1.tv_sec); 
+0

@Kornelije ...详细解释。非常感谢。对不起,延迟..在过去的几天里没有了。 –

+3

注意:'gettimeofday'在POSIX 2008中已经过时,而是引入'clock_gettime',可能需要使用'-lrt'链接。不过,它可能还不能在许多平台上使用。在Linux中,这是没问题的。在Mac上,我认为它还不可用。在Windows中,它可能永远不可用。 – Shahbaz

+0

t1.tv_usec是一个long int,srand将一个unsigned int作为输入。 (我遇到了一个问题,它有所作为。) – Jiminion

6

原因是,srand()设置随机生成器的初始状态,并且如果您不在两者之间触摸状态,则生成器生成的所有值只是“随机的”。

例如,你可以这样做:

int getRandomValue() 
{ 
    srand(time(0)); 
    return rand(); 
} 

,然后如果你调用该函数反复,使time()返回邻近的电话相同的价值观,你只得到生成相同的价值 - 这是由设计。

2

函数srand种子的伪随机数发生器。如果你多次呼叫它,你将重新设定RNG。如果你用相同的参数调用它,它将重新启动相同的序列。

为了证明这一点,如果你不喜欢简单的东西:

#include <cstdlib> 
#include <cstdio> 
int main() { 
for(int i = 0; i != 100; ++i) { 
     srand(0); 
     printf("%d\n", rand()); 
    } 
} 

,你会看到相同数量的印刷100次。

+2

问题是关于C,而不是C++。 –

21

随机数实际上是伪随机数。首先设置种子,从rand的每个呼叫获得一个随机数,并修改内部状态,并在下一个rand调用中使用该新状态以获得另一个数字。由于使用某个公式来生成这些“随机数”,因此在每次拨打rand之后设置一个特定的种子值将从呼叫中返回相同的号码。例如,srand (1234); rand();将返回相同的值。一旦使用种子值初始化初始状态将产生足够的随机数,因为您不用srand来设置内部状态,从而使得数字更可能是随机的。我们通常在初始化种子值时使用返回的秒数值time (NULL)。假设srand (time (NULL));处于循环状态。然后循环可以在一秒钟内迭代多次,因此循环中第二个rand调用中循环迭代的次数将返回相同的“随机数”,这是不希望的。在程序启动时初始化一次将设置种子一次,并且每调用一次rand,就会生成一个新数字并修改内部状态,因此下一个呼叫rand会返回一个足够随机的数字。

例如这个码由http://linux.die.net/man/3/rand

static unsigned long next = 1; 
/* RAND_MAX assumed to be 32767 */ 
int myrand(void) { 
    next = next * 1103515245 + 12345; 
    return((unsigned)(next/65536) % 32768); 
} 
void mysrand(unsigned seed) { 
    next = seed; 
} 

内部状态next被声明为全局的。每个myrand调用将修改内部状态并更新它,并返回一个随机数。每次调用myrand将有不同的next值,因此该方法会在每次调用时返回不同的号码。

看看mysrand的实现;它只是设置您传递给next的种子值。因此,如果在调用rand之前每次将next的值设置为相同,那么它将返回相同的随机值,因为应用了相同的公式,这是不可取的,因为该函数是随机的。

但根据您的需要,您可以将种子设置为某个特定值,以生成每次运行的相同“随机序列”,例如针对某个基准或其他基准。

+3

我必须说你的答案是这个问题最详细的答案。完美地解释了几乎'兰特'和'斯兰'的工作原理。 – manty

+0

你的意思是(无符号长种子)mysrand()的参数吗? – Jiminion

+0

@Jiminion这是'man srand'的代码片段。范围从0到32767(假设RAND_MAX),远小于“long”范围。由于内部乘法和加法将超出'unsigned int'的范围,因此状态变量'next'被设置为'long'。之后,结果在上述指定范围内缩放或修改。虽然你可以让种子“长”。 – phoxis

1

使用srand为应用程序实例生成不同种子的简单解决方案可以在同一秒内运行。

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

这种方法使你的种子非常接近随机,因为没有办法猜测你的线程什么时候开始,并且pid也会不同。

4

简短回答:打电话srand()不是就像随机数发生器的“滚动骰子”。它也不像洗牌一样。如果有的话,它更像是一副扑克牌。

想想这样吧。从一副大卡牌中获得一定数量的交易,每次你打电话时,只需从甲板顶部拿下下一张卡片,给你价值,然后将该卡牌返回到甲板的底部。 (是的,这意味着经过一段时间的“随机”序列会重复这是一个非常大甲板,但:。通常4,294,967,296卡)

而且,每次你的程序运行时间,卡全新包装是从游戏商店购买的,每一款全新的套牌总是具有相同的顺序。所以除非你做了一些特别的事情,每次你的程序运行时,它会从rand()返回完全相同的“随机”数字。

现在,你可能会说:“好吧,那么我该如何洗牌?”答案是(至少就randsrand而言),没有办法改组甲板。

那么srand是做什么的?根据我在这里建立的比喻,打电话srand(n)基本上就像是说,“从顶部削减卡牌n”。但等一等,还有一件事:它实际上是另一个全新的甲板,并从顶部削减它n卡。

所以,如果你srand(n)rand()srand(n)rand(),...,与同n每一次,你不会只是得到一个不是非常随机序列,你就会得到相同数量的背每次从rand()。 (不一定是你交给srand相同数量,但同样的数量从rand一遍又一遍回来。)

所以你能做的最好的就是削减甲板一次,就是叫srand()一次,你的程序的开始,这是一个合理随机的n,这样你就可以在每次程序运行时从一个不同的随机位置开始。

[P.S.是的,我知道,在现实生活中,当你购买一副全新的卡片时,它通常是按顺序排列的,而不是随机排列的。为了让这里的比喻起作用,我想象你从游戏商店购买的每张牌组都是以一种看似随机的顺序,但是与你从同一家商店购买的其他牌组完全相同,看似随机的顺序。有点像他们在桥牌比赛中使用的牌一样。]

0

1 \看起来每次rand()运行时,它都会为下一个rand()设置一个新的种子。如果srand()运行多次,问题是如果两次运行发生在一秒钟内(时间(NULL)不变),则下一个rand()将与rand()相同,在之前的srand()之后。

+0

主要的一点是用'srand()'初始化几次相同的种子会导致'rand()'返回相同的值。 –

相关问题