srand(time(NULL)) 产生类似的结果[重复]
Posted
技术标签:
【中文标题】srand(time(NULL)) 产生类似的结果[重复]【英文标题】:srand(time(NULL)) generating similar results [duplicate] 【发布时间】:2011-07-12 17:18:31 【问题描述】:我不明白为什么 srand() 在运行之间生成如此相似的随机数!
我正在尝试运行以下代码
srand ( time(NULL) );
int x = rand();
cout << x << endl;
但是,我总是得到几乎相同的数字,而不是一个合适的随机数,随着时间的推移,这个数字增长缓慢。所以我得到如下数字:11669、11685、11701、11714、11731。
我做错了什么?
我正在使用 Visual Studio 2010 SP1。
好的,srand() 真的那么简单吗?我的意思是有人怎么会称它为随机函数?
srand(1) => rand() = 41
srand(2) => rand() = 45
srand(3) => rand() = 48
srand(4) => rand() = 51
....
【问题讨论】:
每次拨打rand()
时你都在播种吗?只需播种一次!
你用当前时间初始化,想知道为什么它会慢慢增加?
我到处读到它是在 C++ 应用程序中初始化 srand 的正确方法。我每个 main() 只做一次。
从字里行间看,我猜你的程序只产生一个数字,而你正在多次运行它——对吗?
是的,srand
使用类似的种子启动它时产生类似的结果是完全正常的。
【参考方案1】:
首先,srand()
不是随机函数;它设置了起点
的伪随机序列。有点令人惊讶的是,你的
rand()
的实现似乎正在返回一个基于
以前的状态,而不是新计算的状态,所以第一个
调用srand()
后的值很大程度上取决于传递给的值
srand()
。如果你要写:
srand( time( NULL ) );
rand();
std::cout << rand() << std::endl;
,我相信您会看到更多不同。
FWIW:我在 Windows 和 Linux 上都尝试了以下操作:
int
main()
srand( time( NULL ) );
int r1 = rand();
std::cout << r1 << ' ' << rand() << std::endl;
return 0;
每隔一秒调用 10 次,我得到:
16391 14979
16394 25727
16397 3708
16404 25205
16407 3185
16410 13933
16417 2662
16420 13411
16427 2139
在 Windows 下使用 VC++——您会注意到
第一次打电话给rand()
——和
1256800221 286343522
955907524 101665620
1731118607 991002476
1428701871 807009391
44395298 1688573463
817243457 1506183315
507034261 1310184381
1278902902 54648487
2049484769 942368151
1749966544 1833343137
在 Windows 下使用 g++;在这种情况下,即使读取的第一个值也是 比较随机。
如果您需要一个好的随机生成器,您可能必须使用一个 来自升压;该标准并没有太多说明应该是什么算法 使用,并且实现的质量差异很大。
【讨论】:
大约五年前,我在我们产品的 Windows 版本的生产代码中遇到了这个问题。解决方案是在播种后吃掉第一个 rand() 调用,仅适用于 Windows。我对 Windows、AIX 和 Linux 进行了广泛的分析(数十亿个样本),并在所有三个测试环境中得到了可接受的相似结果。我还花时间使用了更好的种子值(以毫秒为单位的当前时间 % 32000 + 进程的 pid,类似的东西)。【参考方案2】:确保你在做
srand ( time(NULL) );
while(condition)
int x = rand();
cout << x << endl;
而不是
while(condition)
srand ( time(NULL) );
int x = rand();
cout << x << endl;
每次迭代都会改变种子的第一种方式。第二种方法是在每次迭代时对非常相似的种子执行随机函数(因为时间变化不大)。
【讨论】:
后者之所以行不通是因为当前时间更新的不够频繁,所以很多次迭代会读取相同的时间,因此使用相同的种子。 我就是这样做的。 int main(int argc, char* argv[]) srand ( time(NULL) ); ..... 该代码不会打印出多个结果。您给了我们一系列数字,但您显示的唯一代码打印出一个数字。此外,理论上的while
可能只是程序的多次运行。【参考方案3】:
如果你想连续快速运行程序,每次得到不同的随机数,用当前时间初始化是错误的做法。你需要的是熵的来源; this question 可能会让您入门。将 time(NULL)
替换为 QueryPerformanceCounter()
可能是一个好的开始,因为它更新得更快,但它仍然有些可预测 - 我不知道这对你是否重要。
【讨论】:
很高兴知道QueryPerformanceCounter()
播种
@Kyle,不幸的是 QueryPerformanceCounter 仅适用于 Windows。 Linux 使用 /dev/random 有一个更好的解决方案,尽管它涉及打开和关闭文件。
@Mark time
似乎是最好的便携式解决方案,但大多数系统都有很多不同的值可以使用。很长一段时间,我习惯使用time
的hash,进程id和机器IP地址,这样两个人同时启动程序仍然会得到完全不同的序列。 (当然/dev/random
更好,也是我今天在Unix下使用的。)
我在这里使用 QueryPerformanceCounter() 做了一个 sn-p:pastebin.com/DGxZZuRN【参考方案4】:
由于您拥有 Visual Studio 2010,因此您可以使用现代 C++ 中的可移植 random device interface 而不是 time() 来播种 srand():
#include <iostream>
#include <random>
#include <cstdlib>
int main()
std::random_device rd;
std::srand(rd());
std::cout << std::rand() << '\n';
现在重复运行程序仍然会产生不同的值。相同的代码将适用于 Linux 上的 GNU g++ 或任何其他现代编译器。
【讨论】:
酷,这是我的新作品。它是当前标准的一部分,还是 C++0x 扩展? @Mark Ransom 它是 TR1 扩展的一部分,包含在 C++0x 中【参考方案5】:好的,Mark Ransom 的所有功劳都归功于他解释实际发生的事情的答案。我在他的链接问题中没有找到源代码,所以我用谷歌搜索了它,发现这个在 Windows 上完美运行。因此,对于 windows 上的 srand,这里是生成更好的 srand() 种子的源代码。
#include <windows.h>
int main()
LARGE_INTEGER cicles;
QueryPerformanceCounter(&cicles);
srand (cicles.QuadPart);
return 0;
【讨论】:
【参考方案6】:我也遇到了同样的问题。即使在几十秒之后,这些种子也太相似了。因为我以这种方式得到我的号码:
int FlRandomInt(int LowerLimit, int UpperLimit)
int Result;
Result = rand();
Result=LowerLimit+Result*(UpperLimit-LowerLimit)/RAND_MAX;
return Result;
我知道这不是获取整数的最佳方法,但我使用相同的过程来生成随机浮点数和双精度数,因此最好验证它们是否有显着差异,而不是仅在最后一个小数处。
无论如何,我只是想发布一个适合我的解决方案。它只是将时间种子乘以 100:
srand(( unsigned )time( 0 ) * 100 );
希望它有所帮助,即使我确信有更优雅的方法来解决这个问题。
【讨论】:
调用一个虚拟 rand();在 srand() 之后;使其更加独特。或者使用我回答中的代码:***.com/questions/6668282/…【参考方案7】:从@James Kanze 的测试看来,这似乎是 VC++ 的 C 运行时的一个特性(尽管我确信其他库也会受到同样的影响)。这个库也有minimum allowableRAND_MAX,但这是另一个问题。
初始值的低方差的解决方法是简单地丢弃它:
void seed_rand( unsigned int seed )
srand( seed ) ;
(void)rand() ;
int main()
seed_rand( time( NULL ) );
int r1 = rand();
std::cout << r1 << ' ' << rand() << std::endl;
return 0;
【讨论】:
【参考方案8】:#include"stdio.h" //rmv coding for randam number access using c++
#include"conio.h"
#include"time.h"
void main()
time_t t;
int i;
srand(time(null));
for(i=1;i<=10;i++)
cout<<(unsigned)rand()%100-90<<"\t";
for(i=1;i<=10;i++)
cout<<(char)rand()%100-90<<"\t";
getch();
【讨论】:
以上是关于srand(time(NULL)) 产生类似的结果[重复]的主要内容,如果未能解决你的问题,请参考以下文章
c语言哪个时间函数是精确到毫秒的?使用srand(time(NULL))的话,如果在同一秒运行程序