需要一个用于 C++ 的快速随机生成器 [关闭]

Posted

技术标签:

【中文标题】需要一个用于 C++ 的快速随机生成器 [关闭]【英文标题】:Need a fast random generator for c++ [closed] 【发布时间】:2010-12-11 01:08:44 【问题描述】:

我正在尝试在我的 TSP 生成器上为欧几里得距离进行一些 opt-3 交换,并且由于在许多情况下我有超过 500 个节点,我需要随机选择我想要的 3 个节点中的至少 1 个尝试交换。

所以基本上我需要一个快速的随机数函数。 (普通的 rand() 太慢了)它不必太棒了,只要很好 足够

编辑: 我忘了提一下,我正坐在一个环境中,除了标准语言库(例如 STL、iostream 等)之外,我无法添加任何库。所以没有提升=/

【问题讨论】:

听起来像我的问题:***.com/questions/1046714/…(我使用了五行 XORshift 生成器。) @GManNickG:rand() 实现是特定于平台的。在不知道具体实现的情况下如何判断它的速度? @GManNickG:“MT 通常比 rand() 更快,或者几乎一样快,具有更好的特性……”?你怎么知道它一开始就没有实现机器翻译? Xorshit+ 生成 64 位随机数并通过 BigCrush:en.wikipedia.org/wiki/Xorshift#Xorshift.2B 这里是快速浮点随机数生成器的三种实现,您可能会觉得有用:musicdsp.org/showone.php?id=273 【参考方案1】:

尽管这篇文章已有多年历史,但它在我寻找类似答案时出现了,而我最终使用的答案甚至不在其中。所以我添加了我找到的那个;

#include <random> msdn entry

这种方法将构建一个自包含的随机生成器,我发现它比rand()%x 随机得多;几十万次迭代。 rand()% 永远不会连续抛出 16 个以上的正面/反面,而应该每隔 65k 次尝试。这个不仅做到了,而且在四分之一的时间内做到了。

这就是我自己实现#include <random>的方式:

//create rng_gen, using mt technique, with range 0,1 (coin) and 1,6(dice);
std::random_device rd; //seed
std::mt19937 gen(rd()); //seed for rd(Mersenne twister)
std::uniform_int_distribution<> rng_coin(0, 1); //rng1 range
std::uniform_int_distribution<> rng_dice(1, 6); ///rng2 range

rng_coin(gen); //will apply rng1 range on (gen) object. Is very fast
rng_dice(gen); //will apply rng2 range, returns int.

//will output 1000 cointosses to console
for (int i=0;i<1000;++i)std::cout<<rng_coin(gen)<<"\n";
//will generate 1000 dice throws
for (int i=0;i<1000;++i)rng_dice(gen);

【讨论】:

【参考方案2】:

从Ivy Bridge 架构开始,Intel 添加了RdRand CPU 指令,AMD 在 2015 年 6 月晚些时候添加了它。因此,如果您的目标处理器足够新并且不介意使用(内联)汇编,那么最快的方法生成随机数应该在调用RdRand CPU 指令以获取 16 位或 32 位或 64 位随机数,如here 所述。滚动到页面中间的代码示例。在该链接上还有一个代码示例,用于检查当前 CPU 是否支持 RdRand 指令,另请参阅 Wikipedia 以了解如何使用 CPUID 指令执行此操作。

相关问题:Making use of sandy bridge's hardware true random number generator?(尽管根据***,RdRand 指令首先出现在 Ivy Bridge 中,但不是该问题所说的 Sandy Bridge 架构)

基于_rdrand64_step() 的示例 C++ 代码:

#include <immintrin.h>

uint64_t randVal;
if(!_rdrand64_step(&randVal)) 
  // Report an error here: random number generation has failed!

// If no error occured, randVal contains a random 64-bit number

【讨论】:

rdrand 实际上很慢。参见software.intel.com/en-us/articles/… 和***.com/questions/10484164/… 的3.4.1。在快速基准测试中,xorshift128 的时钟比rdrand32 快约 13 倍。英特尔声称 70 - 200 MB/s/线程连续。【参考方案3】:

英特尔网站的两个不错的选择:

1) fastrand - 它比 std rand() 快 2.01 X。该例程返回一个整数,与 C lib 类似的输出值范围。

inline int fastrand()  
  g_seed = (214013*g_seed+2531011); 
  return (g_seed>>16)&0x7FFF; 
 

2) SSE 版本(见下面的链接)大约是 std rand() 的 5.5 倍,但是它一次生成 4 个随机值,需要一个带有 sse 的处理器(几乎所有都这样做),并且更复杂。

http://software.intel.com/en-us/articles/fast-random-number-generator-on-the-intel-pentiumr-4-processor/

【讨论】:

很好,使用它而不是 rand() 在 Tegra 3 上将例程加快了大约 2.5 倍。 这太棒了!我必须生成几百万个随机数,这带来了令人难以置信的加速。 什么是g_seed? long? long long? g_seedstatic unsigned int SSE版本并不比pcg32_fast快,既简单又优秀:en.wikipedia.org/wiki/…【参考方案4】:

Boost 库有一组随机生成器。性能图表见here。

编辑:这个答案是在编辑原始问题之前出现的。但我希望它仍然有用,所以我把它留在这里。

【讨论】:

更新图表boost.org/doc/libs/1_47_0/doc/html/boost_random/…【参考方案5】:

我觉得 WELL 挺好的,WELL512a 挺短的。 http://www.iro.umontreal.ca/~panneton/WELLRNG.html WELL44497a 在当时也很复杂。但是,WELL 会生成一个介于 0 和 1 之间的数字。

【讨论】:

【参考方案6】:

另一个帖子提到了Marsaglia的xorshf生成器,但是没有人贴出代码。

static unsigned long x=123456789, y=362436069, z=521288629;

unsigned long xorshf96(void)           //period 2^96-1
unsigned long t;
    x ^= x << 16;
    x ^= x >> 5;
    x ^= x << 1;

   t = x;
   x = y;
   y = z;
   z = t ^ x ^ y;

  return z;

我到处都用过这个。唯一失败的地方是当我试图生成随机二进制矩阵时。过去大约 95x95 矩阵,它开始生成太少或太多奇异矩阵(我忘记了)。已经证明这个发生器相当于一个线性移位反馈寄存器。但除非你在做密码学或认真的蒙特卡罗工作,否则这个生成器会很糟糕。

【讨论】:

Numerical Recipes(我知道,这有点值得商榷,因为多年来他们在这些书中写了很多废话)建议不要单独使用 XOR-shift,而只能在组合生成器中使用。跨度> 奇异矩阵太少是应该的,因为奇异矩阵在所有矩阵的空间中都是“奇异的”。 什么是64位版本而不调用这个函数两次?换成 uint64_t 把第一个班次从 16 改成 32 就够了吗? 试过这个,在我的硬件/编译器上它比***页面上的 xorshift128 稍慢。 虽然这是许多赞成的公认答案,但我还发现 Wikipedia 页面中的 xorshift128 在 Skylake 架构上的速度提高了 2.5 倍。 xorshf96 在我的系统上大约需要 4.4ns,而 xorshift128 大约需要 1.4ns【参考方案7】:

请参阅随机数生成器专家 George Marsaglia 的these generators。它们以 C 宏的形式实现,而且速度极快,每个生成的数字只需几个操作。

【讨论】:

【参考方案8】:

rand() 真的很快,我不相信你会发现更快。

如果它实际上让你放慢了速度(我有点怀疑),那么你需要改变架构。

我建议用随机数预先填充一个长列表,然后当您需要一个时,只需从列表中取出一个,而不是生成一个。您可以使用后台线程重新填充列表。

【讨论】:

在现代处理器上,计算新数字比从内存中提取数字要快。 我试过这个,它是迄今为止 Tegra3 上最快的方法,如果你在填充后按顺序迭代数组。缺点是数字会在短时间内重复。 相当老的反应,但@MarkRansom:你确定吗?拥有一个密集的随机数列表(可以改进缓存和预取)应该比任何足够好的随机数生成要快得多。或者你有其他显示的代码吗? xor_shift gens 比 rand() 快大约 6-10 倍 在一天结束时。衡量,不要简单地相信你被告知的内容。处理器 A 可能很棒的东西在处理器 B 上可能不是最理想的。【参考方案9】:

Mersenne Twister 有一些快速实现。

【讨论】:

MT19937 通常比 LCG 更快。还有面向 SIMD 的 Fast Mersenne Twister:math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/index.html,它甚至更快。 Mersenne Twister 是个糟糕的选择 arxiv.org/abs/1910.06437【参考方案10】:

您能否提前预生成一堆随机位并一次将它们剥离 2 个(因为您只需要一个介于 1 和 3 之间的随机数)?

【讨论】:

以上是关于需要一个用于 C++ 的快速随机生成器 [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

C++中的随机生成算法

轻量级 C++ 图像库 [关闭]

如何在 N 个较小的矩形上拆分一个大矩形以使其看起来随机? [关闭]

java中产生随机数的函数是啥

任何好的教程可以帮助我创建用于在 C、C++ 中随机化的头文件 [关闭]

C++ 快速排序枢轴优化