定义概率分布代价是否昂贵?

时间:2013-10-31 12:07:32

标签: c++ optimization probability

我正在编写一个物理模拟编码,现在我觉得需要优化它。我正在考虑改进一点:我的一个方法之一(在几种情况下我称之为十亿次)每次定义一个概率分布。这是代码:

void myClass::myMethod(){ //called billions of times in several cases
uniform_real_distribution<> probd(0,1);
uniform_int_distribution<> probh(1,h-2);
uniform_int_distribution<> probv(1,v-2);
    //rest of the code
}

我可以将分发作为类的成员传递,这样我就不必每次都定义它们吗?只需在构造函数中初始化它们,并在h和v更改时重新定义它们?这可能是一个很好的优化进展吗?最后一个问题,当使用标志-O3或-O2编译时,编译器(在我的情况下是g ++)是否已经纠正了这个问题?

提前谢谢!

更新:我对它进行了编码并对两者进行了计时:程序实际上变慢了(几个百分点)所以我回到了我的开始:在每个循环中创建概率分布

3 个答案:

答案 0 :(得分:5)

答案答:我不应该这么认为,对于统一分布,它只是将参数值复制到位,可能只需要少量算术,并且可以很好地优化。

但是,我相信分发对象可以有状态。它们可以使用来自对生成器的调用的部分随机数据,并且允许保留下次使用分布时使用的其余随机性,以便减少对生成器的调用总数。因此,当您销毁分发对象时,您可能会丢弃一些可能代价高昂的随机数据。

答案B:停止猜测并测试它。

为您的代码计算时间,然后将static添加到probd的定义中并再次计时。

答案 1 :(得分:2)

  1. 嗯,可能有一些优势,但AFAIK这些物品的构造并不是真正的重量级/昂贵。此外,对于本地人,您可以在数据位置和优化程序可以做出的假设中获得一些东西。
  2. 我不认为它们会自动作为类变量移动(特别是如果你的类是POD - 在这种情况下我怀疑编译器是否敢于修改它的布局);最有可能的是,它们完全被优化掉 - 只有被调用方法的代码 - 特别是operator() - 可能会保留,直接引用h和v。但必须通过查看生成的程序集来检查它。
  3. 顺便提一下,如果你遇到性能问题,除了优化明显的点(内部循环中使用的非最佳算法,连续内存分配,删除无用的大对象副本,......)之外,你应该尝试使用分析器来找到代码中真正的“热点”,集中精力优化它们,而不是随机遍历所有代码。

答案 2 :(得分:2)

uniform_real_distribution维护类型为param_type的状态,即两个double值(使用默认模板参数)。构造函数赋予这些并且在其他方​​面是微不足道的,析构函数是微不足道的。

因此,与初始化1指针(或引用)或通过double进行间接寻址相比,在函数中构造临时值会产生2 this个值的开销。从理论上讲,它可能因此更快(但出现更快,或者运行速度更快更有必要)。由于它没有太大的作用,因此即使它是微观优化也是值得尝试和计时是否存在差异。

大约3-4个额外的周期通常是可以忽略的,但是因为你说“数十亿次”,它当然可以很好地产生可测量的差异。在3GHz机器上,3个周期乘以10亿次是1秒。

当然,没有剖析的优化总是有点......尴尬。您可能会发现代码中不同的部分被称为数十亿次,可以节省更多的周期。

修改
由于您不打算对其进行修改,并且由于第一个分布是使用文字值初始化的,因此您实际上可能使其成为常量(例如constexpr或命名空间级别{{1 }})。无论如何,这应该允许编译器在任何情况下生成最有效的代码。