我是一名物理学家,编写的程序涉及从高斯分布中生成几个(数十亿的数量级)随机数。我正在尝试使用C ++ 11。这些随机数的生成由一个应该花费很少时间的操作分开。我最担心的是,如果我生成如此多的随机数,并且时间间隔很小,则可能导致性能欠佳。我正在测试某些统计属性,这些属性严重依赖于数字随机性的独立性,因此,我的结果对这些问题特别敏感。我的问题是,我在下面的代码中提到的数字类型(我的实际代码的简化版本),我做的事情显然(甚至是巧妙的)错误吗?
#include <random>
// Several other includes, etc.
int main () {
int dim_vec(400), nStats(1e8);
vector<double> vec1(dim_vec), vec2(dim_vec);
// Initialize the above vectors, which are order 1 numbers.
random_device rd;
mt19937 generator(rd());
double y(0.0);
double l(0.0);
for (int i(0);i<nStats;i++)
{
for (int j(0);j<dim_vec;j++)
{
normal_distribution<double> distribution(0.0,1/sqrt(vec1[j]));
l=distribution(generator);
y+=l*vec2[j];
}
cout << y << endl;
y=0.0;
}
}
答案 0 :(得分:6)
允许normal_distribution
拥有州。并且通过这种特定的分布,通常与每个其他调用成对地生成数字,并且在奇数调用上,返回第二个缓存的数字。通过在每次调用中构建新的分发,您将丢弃该缓存。
幸运的是,你可以&#34;塑造&#34;通过使用不同的normal_distribution :: param_type&#39; s来调用单个分布:
normal_distribution<double> distribution;
using P = normal_distribution<double>::param_type;
for (int i(0);i<nStats;i++)
{
for (int j(0);j<dim_vec;j++)
{
l=distribution(generator, P(0.0,1/sqrt(vec1[j])));
y+=l*vec2[j];
}
cout << y << endl;
y=0.0;
}
我不熟悉std::normal_distribution
的所有实现。但是我为libc++写了一个。所以我可以肯定地告诉你,我对你的代码的轻微改写将产生积极的性能影响。我不确定它会对质量产生什么影响,只是说我知道它不会降低质量。
<强>更新强>
关于Severin Pappadeux下面关于在分布中一次生成数字对的合法性的评论:请参阅N1452讨论并允许这种技术的地方:
分布有时会存储来自其相关来源的值 调用其运算符的随机数()。例如,一个常见的 生成正态分布随机数的方法是 检索两个均匀分布的随机数并计算两个 正常分布的随机数。为了重置 分发的随机数缓存到定义的状态,每个 发行版具有重置成员功能。应该在a上调用它 交换或恢复相关引擎时的分配。
答案 1 :(得分:1)
关于优秀HH回答的一些想法
N(μ,sigma)= mu + N(0,1)* sigma
如果您的平均值(mu)始终为零,则可以通过执行类似
之类的操作来简化和加速(通过不添加0.0)代码normal_distribution<double> distribution;
for (int i(0);i<nStats;i++)
{
for (int j(0);j<dim_vec;j++)
{
l = distribution(generator);
y += l*vec2[j]/sqrt(vec1[j]);
}
cout << y << endl;
y=0.0;
}
如果速度至关重要,我会尝试预先计算主要10 ^ 8循环之外的所有内容。是否可以预先计算sqrt(vec1 [j]),以便节省sqrt()调用?是否有可能 将vec2 [j] / sqrt(vec1 [j])作为单个向量?
如果无法预先计算这些向量,我会尝试节省内存访问。保持vec2 [j]和vec1 [j]的各个部分可能有助于获取一个缓存行而不是两个。因此,请声明vector<pair<double,double>> vec12(dim_vec);
并在抽样y+=l*vec12[j].first/sqrt(vec12[j].second)