【问题标题】:Optimizing the use of the C++11 random generator优化 C++11 随机生成器的使用
【发布时间】:2013-12-04 08:47:43
【问题描述】:

我正在大量使用随机数编写物理模拟,我只是第一次分析我的代码,所以我在读取输出时可能有误,但我看到这条线首先出现:

   %   cumulative   self              self     total           
 time   seconds   seconds    calls  ms/call  ms/call  name  
 90.09     21.88    21.88   265536     0.08     0.08  std::mersenne_twister_engine<unsigned long, 32ul, 624ul, 397ul, 31ul, 2567483615ul, 11ul, 4294967295ul, 7ul, 2636928640ul, 15ul, 4022730752ul, 18ul, 1812433253ul>::operator()()

这似乎意味着生成数字生成器需要 90% 的时间。 我已经写过一篇文章,询问是否不在每个循环中构建随机概率分布是否可以节省我的时间,但在尝试和计时之后它并没有帮助(Is defining a probability distribution costly?)。是否有优化随机数生成的常用选项?

提前感谢您,我的模拟(在当前状态下)运行了几天,因此减少 90% 的计算时间将是一个重大进展。

【问题讨论】:

  • 这取决于您关心的是什么,对于不同的情况有大量不同的 PRNG,您想要线性的还是不线性的?适用于无符号整数、浮点数、int ... 的东西?
  • 你考虑过/正在使用线程吗?
  • 您是否考虑过在运行模拟之前生成随机数或者这不可能?
  • @claptrap:是的,我考虑过这一点,但不幸的是,这似乎不可能,因为我不知道我需要多少随机数以及我的概率密度边界在模拟过程中会发生变化.
  • @MSalters 呃,你说的线程是什么意思?并行化?

标签: c++ optimization c++11 random


【解决方案1】:

使用专用的随机数库。

我建议WELL512(链接包含论文和源代码)。

【讨论】:

  • 那有什么用?代码的可移植性会降低,而且完全不清楚它是否会更快。您仍然存在效率和随机性之间权衡的基本问题。
  • 是的,当然。另一方面,众所周知,Well512 比 mersenne twister 效率高得多,同时提供类似的保证。目前投票率最高的答案是“自己实现”——我觉得使用专门用于手头任务的库是更好的解决方案。
  • Wilbert,同意自己实现
【解决方案2】:

一方面,效率(即速度和大小(状态的字节数))与任何 RNG 的“随机性”之间总是需要权衡取舍。 Mersenne twister 具有相当好的随机性(前提是您使用高熵种子,例如 std::random_device 提供的),但速度慢且状态大。 std::minstd_randstd::knuth_b(线性同余)更快,ranlux48(斐波那契)更快,但随机性较低(通过较少的随机性测试,即具有一些非随机光谱特性)。如果您对所提供的随机性感到满意(即随机数据中没有意外的相关性),只需进行试验和测试。


edit: 1 当然,所有这些 RNG 都不是真正随机的,而且对于密码学来说也不够随机。如果您需要,请使用std::random_device,但不要抱怨速度。 2 并行使用(您应该考虑)使用thread_local RNG,每个都使用另一个种子进行初始化。

【讨论】:

  • 感谢您的建议,我使用的第一个随机生成器(提供了 crand)在我的数据中显示了一些奇怪的相关性。阅读他们的文档后,我可能会尝试您的建议!
  • @Liam 在该频谱的另一端是 CSPRNG,我可以保证它会更慢,但你可以知道你的相关性在晚上睡觉参考不会有问题(Dual_EC_DRBG 无法承受;感谢 NSA)。 Hash-DRBG 或 HMAC-DRBG 结合 strong 加密摘要算法(例如 SHA256)肯定会给您所需的分散性,但如果您认为 MT 很昂贵,那您就没有还没有看到任何东西。但是,对于非 LCG 算法,您可能会发现具有 2^19937-1 周期的 MT 与您可能获得的一样好。
【解决方案3】:

如果您的代码大部分时间都会产生随机数,您可能需要花一些时间为您的应用程序选择最佳算法并自己实施。 Mersenne Twister是一种非常快速的算法,并且随机性良好,但是您可以随时折衷所产生的随机数的质量。这取决于您的模拟需要什么以及您生成的数字类型(整数或浮点数)。如果您绝对需要良好的随机性,Mersenne Twister 可能已经是您的最佳选择之一。否则,您可能希望在代码中实现一个简单的linear congruential generator

要注意的另一件事是,如果您的代码是并行的,您应该使用随机数生成器的可重入版本,并确保不同的线程对其生成器使用自己的内部状态变量。否则,避免覆盖生成器的内部状态变量的互斥锁会大大降低您的代码速度。请注意,许多库生成器是不可重入的。如果您的代码不行,则应该可能并行化它并使用单独的线程填充随机数列表以供模拟以消耗。另一种选择是使用 GPU 并行生成随机数。

以下是一些链接比较不同生成器的性能: http://www.boost.org/doc/libs/1_38_0/libs/random/random-performance.html https://www.gnu.org/software/gsl/manual/html_node/Random-Number-Generator-Performance.html

【讨论】:

  • “使用 RNG 的可重入版本” - 因为我们在谈论 C++11,所以这不是一个大问题。 RNG现在是正确的对象,并且适用通常的对象规则:它们不重新入口,如果线程需要共享一个互斥锁。 span>
  • - 1“自己实现它 i>”是错误的答案,因为它可以得到。 span>
  • 当库代码花费 90% 的运行时间时,自己实现是一个完全有效的策略。随机数生成器并不复杂。使用您自己的代码,您可以找到并修复瓶颈,在图书馆代码中无法执行。通过切换远离标准库并实现自己的堆,地图和列表结构,我曾一倍增加了模拟代码的速度。此外,还有readily available 的快速实现,他可以下载并集成到他的代码中。
【解决方案4】:

Marsaglia 的KISS RNG 速度很快,非常适合模拟工作。我假设您不需要加密质量。

【讨论】:

  • 迂腐评论:您链接的版本假定无符号长整数中正好有 32 位
  • KISS 有许多不同尺寸的版本。那只是我遇到的第一个。
  • 我知道(我喜欢那个 rng!)——我的意思是这个特定版本是为 32 位制作的,但是 unsigned long 可能更大
【解决方案5】:

如果随机性要求允许,您可以使用RDTSC instruction 获取随机数,例如int from0to9 = rdtsc() % 10.

【讨论】:

    猜你喜欢
    • 2013-11-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-25
    • 2021-05-23
    • 2014-04-02
    • 2015-10-03
    • 2018-11-10
    相关资源
    最近更新 更多