我正在研究在格子中移动的粒子的随机游走模拟。出于这个原因,我必须创建大量的随机数,大约10 ^ 12及以上。目前,我正在使用C ++ 11提供<random>
的可能性。在分析我的程序时,我发现<random>
花费了大量时间。绝大多数这些数字在0到1之间,均匀分布。在这里,我需要一个二项分布的数字。但重点在于0..1数字。
问题是:如何减少生成这些数字所需的CPU时间以及对其质量有何影响?
正如您所看到的,我尝试了不同的引擎,但这对CPU时间没有太大影响。此外,我的uniform01(gen)
和generate_canonical<double,numeric_limits<double>::digits>(gen)
无论如何有什么区别?
编辑:通过阅读答案,我得出的结论是,我的问题没有理想的解决方案。因此,我决定首先使我的程序具有多线程功能,并在不同的线程中运行多个RNG(以一个random_device编号+一个线程单独增量播种)。目前这种接缝是最不可避免的步骤(无论如何都需要多线程)。作为进一步的步骤,等待确切的要求,我考虑切换到建议的英特尔RNG或Thrust。这意味着我的RNG实现不应该是复杂的,当前不是。但是现在我喜欢专注于我的模型的物理正确性,而不是编程的东西,只要我的程序输出在物理上是正确的。 Thrust Concerning Intel RNG
以下是我目前所做的事情:
class Generator {
public:
Generator();
virtual ~Generator();
double rand01(); //random number [0,1)
int binomial(int n, double p); //binomial distribution with n samples with probability p
private:
std::random_device randev; //seed
/*Engines*/
std::mt19937_64 gen;
//std::mt19937 gen;
//std::default_random_engine gen;
/*Distributions*/
std::uniform_real_distribution<double> uniform01;
std::binomial_distribution<> binomialdist;
};
Generator::Generator() : randev(), gen(randev()), uniform01(0.,1.), binomial(1,1.) {
}
Generator::~Generator() { }
double Generator::rand01() {
//return uniform01(gen);
return generate_canonical<double,numeric_limits<double>::digits>(gen);
}
int Generator::binomialdist(int n, double p) {
binomial.param(binomial_distribution<>::param_type(n,p));
return binomial(gen);
}
答案 0 :(得分:3)
您可以预处理随机数并在需要时使用它们。
如果您需要真正的随机数,我建议您使用像http://www.random.org/这样的服务来确保通过环境环境计算的随机数而不是某些算法。
而且,谈到随机数,您还必须检查:
答案 1 :(得分:1)
如果您需要大量的随机数,我的意思是MASSIVE,请在互联网上仔细搜索IBM的浮点随机数生成器,这可能是十年前发布的。您必须购买PowerPC机器或带有融合乘法附加功能的新型Intel机器。他们以每个核心每个周期一个的速率获得随机数。因此,如果您购买了新的Mac Pro,您每秒可能会获得大约500亿个随机数。
答案 2 :(得分:1)
也许不是使用CPU而是可以使用GPU同时生成多个数字?
http://http.developer.nvidia.com/GPUGems3/gpugems3_ch37.html
答案 3 :(得分:0)
在我的i3上,以下程序在大约五秒内运行:
#include <random>
std::mt19937_64 foo;
double drand() {
union {
double d;
long long l;
} x;
x.d = 1.0;
x.l |= foo() & (1LL<<53)-1;
return x.d-1;
}
int main() {
double d;
for (int i = 0; i < 1e9; i++)
d += drand();
printf("%g\n", d);
}
而将drand()
调用替换为以下结果导致程序在大约十秒内运行:
double drand2() {
return std::generate_canonical<double,
std::numeric_limits<double>::digits>(foo);
}
使用以下代替drand()
也会导致程序在大约十秒内运行:
std::uniform_real_distribution<double> uni;
double drand3() {
return uni(foo);
}
上面的hacky drand()
可能比标准解决方案更适合您的目的..
答案 4 :(得分:-2)
OP要求获得
的答案 <强> 1。生成速度 - 假设一组10E+012
随机数为&#34; 大量&#34;
和
<强> 2。生成器的质量 - 假设数字在一定范围内均匀分布的假设也是随机的
然而,有更多的基本方面需要解决并成功解决实际系统:
A. 定义,是否需要为系统模拟提供保证重复性的随机数序列,以便将来重新运行实验
如果不是这种情况,重新运行模拟实验将主要产生不同的结果,然后随机数发生器过程(或预随机化器和随机选择器)不必担心它们的重新生成 - 中,完全运行的操作模式,实现起来会更简单。
B。定义生成的随机数证明随机性所需的级别(或生成的随机数集必须属于哪个级别)一些特定的统计理论定律(一些已知的合成分布或真正随机的,随机数集的最大Kolmogorov复杂度))。人们不需要NSA专家来说明真随机序列的数值生成器是一个非常棘手的问题,并且它具有与高随机性产品的生成相关的计算成本。
超混沌和真随机序列在计算上非常昂贵。对于随机性质量敏感的应用程序而言,使用低或差随机生成器不是一种选择(无论市场营销论文如何说,没有MIL-STD或NSA级别的系统会在环境中尝试这种受损的质量,其结果确实很重要那么为什么要在科学模拟中少花钱?如果你不介意错过这么多未模拟的模拟现象状态,也许不是问题。
C. 验证您的模拟系统需要多少随机数&#34;根据[usec]消耗多少随机数&#34;以及这个设计要求参数是否是常量,或者可以通过进入多线程,矢量化,基于网格/云的分布式计算框架来扩大规模。
D。在矢量化或网格/云的情况下,您的模拟系统是否需要维护全局或每线程或perGrid / CloudNode-个体访问管理到随机数池的计算策略。
最快 [1]和最佳 [2]解决方案,[D]的选项是预生成最大随机性将质量数写入适当的访问池(并在访问策略和访问管理控制上支付可接受的[C]和[D]成本,以便从池中重新读取,而不是重新生成)。