我想知道将 normal_distribution
放入循环中是否存在问题。
这是以这种奇怪的方式使用 normal_distribution
的代码:
std::default_random_engine generator;
//std::normal_distribution<double> distribution(5.0,2.0);
for (int i=0; i<nrolls; ++i) {
std::normal_distribution<double> distribution(5.0,2.0);
float x = distribution(generator);
}
最佳答案
将 normal_distribution
对象放在循环之外可能比将其放在循环中稍微更有效。当它位于循环内部时,normal_distribution
对象可能每次都会重新构造,而如果它位于循环外部,则仅构造一次。
组件比较。
根据对程序集的分析,在循环外部声明分发
效率更高。
让我们看看两个不同的函数以及相应的程序集。其中一个在循环内声明distribution
,另一个在循环外声明它。为了简化分析,在这两种情况下它们都被声明为 const,因此我们(和编译器)知道分布不会被修改。
您可以看到the complete assembly here.
// This function is here to prevent the compiler from optimizing out the
// loop entirely
void doSomething(std::normal_distribution<double> const& d) noexcept;
void inside_loop(double mean, double sd, int n) {
for(int i = 0; i < n; i++) {
const std::normal_distribution<double> d(mean, sd);
doSomething(d);
}
}
void outside_loop(double mean, double sd, int n) {
const std::normal_distribution<double> d(mean, sd);
for(int i = 0; i < n; i++) {
doSomething(d);
}
}
inside_loop
程序集
循环的程序集如下所示(在 O3 优化时使用 gcc 8.3 编译)。
.L3:
movapd xmm2, XMMWORD PTR [rsp]
lea rdi, [rsp+16]
add ebx, 1
mov BYTE PTR [rsp+40], 0
movaps XMMWORD PTR [rsp+16], xmm2
call foo(std::normal_distribution<double> const&)
cmp ebp, ebx
jne .L3
基本上,它
- 构建分布
- 使用发行版调用 foo
- 测试是否应该退出循环
outside_loop
程序集
使用相同的编译选项,outside_loop
只需重复调用 foo
而无需重新构建发行版。指令更少,并且所有内容都保留在寄存器中(因此无需访问堆栈)。
.L12:
mov rdi, rsp
add ebx, 1
call foo(std::normal_distribution<double> const&)
cmp ebp, ebx
jne .L12
是否有任何理由在循环内声明变量?
是的。确实有在循环内声明变量的好时机。如果您在循环内以某种方式修改分布,那么每次通过再次构造它来重置它是有意义的。
此外,如果您从未在循环外部使用变量,则出于可读性的目的在循环内部声明它是有意义的。
适合 CPU 寄存器的类型(浮点型、整数型、 double 型和小型用户定义类型)通常没有与其构造相关的开销,并且在循环内声明它们实际上可以带来更好的汇编/em> 通过简化编译器对寄存器分配的分析。
关于c++ - 在循环中使用normal_distribution,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55857740/