【问题标题】:random_shuffle algorithm - are identical results produced without random generator function?random_shuffle 算法 - 在没有随机生成器函数的情况下产生相同的结果吗?
【发布时间】:2011-08-09 16:52:07
【问题描述】:

如果标准库中的 random_shuffle 算法没有提供随机生成器函数,如果提供相同的数据,程序的连续运行是否会产生相同的随机序列?

例如,如果

std::random_shuffle(filenames.begin(), filenames.end());

在程序的连续运行中对目录中的相同文件名列表执行,随机序列产生的随机序列是否与先前运行中的相同?

【问题讨论】:

  • 你知道的,你可以试试看... 排队讨论随机播种 :)
  • 我确实得到了相同的结果——只是试图确保这是预期的行为。当然,答案也可能是“是的,这发生了,但这是一个意外,因为行为是未定义的。”
  • BTW std::random_shuffle 在 C++14 中被弃用并在 C++17 中被移除。这是一个更好的方法:stackoverflow.com/a/16969267/2151446

标签: c++ standard-library


【解决方案1】:

如果您使用相同的随机生成器,具有相同的种子和相同的起始 顺序,结果是一样的。毕竟,电脑是 其行为具有确定性(模线程问题和其他一些 零碎的东西)。

如果不指定生成器,则默认生成器为 实现定义。我认为大多数实现都使用 std::rand()(这可能会导致问题,特别是当 序列中的元素大于RAND_MAX)。我会推荐 获得质量已知的生成器并使用它。

如果您没有正确地为正在使用的生成器播种(另一个 不使用默认值的理由,因为你如何播种将取决于 实施),然后你会得到你得到的。如果是 std::rand(),默认总是使用相同的种子。你如何播种 取决于使用的发电机。你用来播种的应该是不同的 从一场跑到另一场;对于许多应用程序,time(NULL) 是 充足的;在 Unix 平台上,我建议阅读很多字节 它来自/dev/random。否则,散列其他信息(IP 机器的地址,进程ID等)也可以改善事情---它 意味着两个用户在同一秒启动程序 仍然会得到不同的序列。 (但这真的只是相关的 如果您在网络环境中工作。)

【讨论】:

  • 我认为std::rand 对于大多数程序来说已经足够了。显然,如果你在玩扑克或密码学,你会想要一个更好的算法。
  • @Billy:RAND_MAX 的值很重要。在 Windows 上它只有 32k,所以也许“大多数程序”只需要小的随机数,但你仍然需要注意限制,你不能认为“我不需要密码安全的不可预测性,因此我可以使用 @ 987654328@".
  • 事实上,我主要考虑的是RAND_MAX 的值(尽管我见过rand 的实现非常非常糟糕)。如果你有超过 32k 的元素,当然,使用rand() 会严重扭曲事情,但是由于实现必须将值映射到[0...n),除非元素的数量比RAND_MAX 少得多,否则会有明显的偏斜。
【解决方案2】:

25.2.11 只是说元素是均匀分布的。它不保证在幕后使用哪个 RNG(除非您传入一个),因此您不能依赖任何此类行为。

为了保证相同的随机播放结果,您需要提供自己的 RNG 来提供这些保证,但我怀疑即使您更新标准库,random_shuffle 算法本身也可能会改变效果。

【讨论】:

  • +1,虽然我不知道“不幸”。即使标准对所使用的 RNG 有所说明,我也希望它允许实现使用rand()。所以至少,之前对srand()rand() 的调用在每次运行时都需要相同,以使结果相同。另外,请注意random_shuffle 的定义实际上并没有说它使用第三个参数;-)
  • @Steve Jessop 说得好,我将删除这个词作为主观词。
  • 我注意到的一件事是,无论默认的 RNG 是什么,它在初始化时总是以相同的值作为种子。在使用 std::random_shuffle 之前不调用 srand(),第一次调用它总是会在同一个容器上产生相同的结果。
  • @Sean:这是通常的方式,因为rand() 需要在程序启动时表现得与使用srand(0) 播种的行为相同。因此,任何使用rand()random_shuffle 实现都会像您观察到的那样运行。一个 linux 实现可以直接从 /dev/random 读取,或者(为了不那么反社会)从 /dev/urandom 播种 PRNG,但是我在我的机器上的 gcc 实现只是使用rand().
【解决方案3】:

您可以在每次运行程序时产生相同的结果。如果这是一个问题,您可以添加一个自定义随机数生成器(可以从外部源播种)作为附加参数 std::random_shuffle。该函数将是第三个参数。有些人推荐random_shuffle 之前调用srand(unsigned(time(NULL)));,但结果通常是实现定义的(并且不可靠)。

【讨论】:

  • 人们当然会打电话给srand(unsigned(time(NULL))); 但我还没有听到任何人推荐它!
  • 关于unsigned(time(NULL)):令人厌烦的迂腐,但C++ 允许time_t 成为浮点类型,并且将超出范围的浮点值转换为整数类型是未定义的行为。愚蠢,因为time_t 的指定比任何人真正需要的都更松散,但它确实存在。关于可移植性的另一个事实,实际上没有人需要知道:-)
猜你喜欢
  • 1970-01-01
  • 2011-11-28
  • 1970-01-01
  • 1970-01-01
  • 2015-02-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多