【问题标题】:srand(time(NULL)) generating similar results [duplicate]srand(time(NULL)) 产生类似的结果[重复]
【发布时间】: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 使用类似的种子启动它时产生类似的结果是完全正常的。

标签: c++ visual-studio visual-studio-2010 random


【解决方案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 );
    

    希望它有所帮助,即使我确信有更优雅的方法来解决这个问题。

    【讨论】:

    【解决方案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();
      
      }
      

      【讨论】:

        猜你喜欢
        • 2014-11-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-07-25
        • 2011-07-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多