【问题标题】:Seeding a random number generator C++ [duplicate]播种随机数生成器C ++ [重复]
【发布时间】:2012-08-10 05:26:25
【问题描述】:

我有两个问题。

  1. 还有哪些其他方法可以在不使用 srand(time(NULL)) 的情况下在 C++ 中播种伪随机数生成器?

  2. 我问第一个问题的原因。我目前使用时间作为生成器的种子,但生成器返回的数字始终相同。我很确定原因是因为存储时间的变量在某种程度上被截断了。 (我有一条警告消息说,“隐式转换失去整数精度:'time_t'(又名'long')到'unsigned int')我猜这告诉我,从本质上讲,我的种子直到明年才会改变发生。就我的目的而言,使用时间作为我的种子就可以了,但我不知道如何摆脱这个警告。

我以前从未收到过该错误消息,所以我认为它与我的 Mac 有关。它是 64 位 OS X v10.8。我也是用Xcode写和编译的,但是在其他电脑上用Xcode没问题。

编辑: 在玩弄和研究了更多之后,我发现了 64 位 Mac 存在的一个错误。 (如果我弄错了,请纠正我。)如果您尝试让您的 mac 使用 time(NULL) 作为种子选择 1 到 7 之间的随机数,您将始终得到数字 4。总是。我最终使用mach_absolute_time() 为我的随机发生器播种。显然,这消除了我程序的所有可移植性......但我只是一个业余爱好者。

编辑2: 源代码:

#include <iostream>
#include <time.h>

using namespace std;

int main(int argc, const char * argv[]) {

srand(time(NULL));

cout << rand() % 7 + 1;

return 0;
}

我再次运行此代码进行测试。现在它只返回 3。这一定与我的计算机有关,而不是 C++ 本身。

【问题讨论】:

  • 就像园艺一样,你只需要种一次种子。
  • 我曾经有类似的行为,我发现初始数字是相同的,但是如果我连续打印一堆随机数,它们就会不同。通常第一个在每次运行中都是相同的,但是到第二次或第三次通过打印循环时它就不同了。尝试连续打印几个并验证运行时它们总是相同的......
  • 你使用对应的 srand() 生成器吗?兰德()?
  • @Redmastif:你错了。 rand() 非常适合我。

标签: c++ random


【解决方案1】:

Tl;dr 但是,很可能,你做错了。你应该只设置一次种子,而你可能有类似的东西:

for ( ... )
{
   srand(time(NULL));
   whatever = rand();
}

应该是什么时候

srand(time(NULL));
for ( ... )
{
   whatever = rand();
}

【讨论】:

  • 如果你因为某种原因不能轻易避免多次播种,你可以使用:srand(rand() ^ time(NULL));。如果重复这样做不会有任何害处。
  • @DavidSchwartz,这可能是什么原因?
  • @eq-: 如果你有一个需要生成随机数的函数,并且你没有简单的方法在函数中判断随机数生成器是否已经播种。例如,所有调用您的代码可能都是您不维护的代码。
  • @DavidSchwartz,我个人认为,由于播种不当,库产生可预测的“随机”结果并没有什么害处,但是是的,这当然是真的。
  • @eq-:这取决于库的用途。如果目的是从根本上提供这些结果,那么当然可以。但是,如果调用者真的没有理由认为库需要 RNG 种子,那可能是一个严重的问题。如果您正在修改当前运行良好的现有库,即使 RNG 没有播种,这一点尤其正确。 (尽管我认为有一点是公平的,如果结果是随机的并不重要,为什么还要麻烦?如果很重要,你不应该使用rand,而是使用更好的东西。)
【解决方案2】:

1. 不是真的。例如,您可以要求用户输入随机种子。或者使用其他一些系统参数,但这不会有什么不同。

2.要消除此警告,您必须进行显式转换。喜欢:

unsigned int time_ui = unsigned int( time(NULL) );
srand( time_ui );

unsigned int time_ui = static_cast<unsigned int>( time(NULL) );

unsigned int time_ui = static_cast<unsigned int>( time(NULL)%1000 );

要检查这是否真的是转换问题,您可以简单地在屏幕上输出时间并查看自己

std::cout << time(NULL);

【讨论】:

  • 我在屏幕上打印了time(NULL),它工作正常。每一秒都在变化。但是,无论我如何调整它们,您的实现都不适合我。接受,因为你至少让我开始了。谢谢。
  • 您是否尝试过在将 time_ui 值提供给 srand() 函数之前检查它?
  • 是的。这种行为方式,几乎就好像种子是由种子中的数字所决定的,而不是数字本身。我这样说是因为当我使用取模运算时,随机数会发生变化。
  • 不,抱歉。我只是做了一个单独的小程序来吐出随机数。使用time(NULL) 种子,程序运行良好。所以我的原始源代码和我捕获随机数的方式还有其他问题。很抱歉用一个毫无意义的问题打扰大家。哈哈。
【解决方案3】:

您应该在程序开始时看到 random 一次:

int main()
{
    // When testing you probably want your code to be deterministic
    // Thus don't see random and you will get the same set of results each time
    // This will allow you to use unit tests on code that use rand().
    #if !defined(TESTING)
    srand(time(NULL));  // Never call again
    #endif

    // Your code here.

}

【讨论】:

    【解决方案4】:

    对于 x86,可以使用直接调用 CPU 时间戳计数器 rdtsc,而不是库函数 TIME(NULL)。下面 1) 读取时间戳 2) 汇编中的种子 RAND:

    rdtsc
    mov edi, eax
    call    srand
    

    对于 C++,以下代码可以使用 g++ 编译器完成。

    asm("rdtsc\n"
        "mov edi, eax\n"
        "call   srand");
    

    注意:但如果代码在虚拟机中运行,则可能不推荐使用。

    【讨论】:

    • 内联汇编不安全;它不会通过函数调用告诉编译器您正在破坏寄存器以及rsp 下面的红色区域。如果它恰好在您的程序中工作,那是 1) 运气和 2) 可能是因为您在编译时禁用了优化,所以编译器无论如何都没有在寄存器中保留任何内容。 不要为此使用内联 ASM。使用__int64 _rdtsc (void) from immintrin.h
    猜你喜欢
    • 1970-01-01
    • 2015-03-14
    • 1970-01-01
    • 2016-08-08
    • 2023-03-18
    • 2019-07-16
    • 2016-07-22
    • 1970-01-01
    • 2013-09-24
    相关资源
    最近更新 更多