0

我有一个粒子系统,通常会创建新粒子,更新它们并破坏......

在发射器模块中有用于重置粒子的 for 循环:

foreach p in particles
    p.position = rand()
    p.velocity = rand()

通常在使用 C 的 rand() 函数时,我们会得到均匀分布,但是当我想使用其他分布(例如高斯分布)时怎么办?

如何更改该代码以使其能够处理几种(或至少两种)不同的方式来生成新粒子的参数?

当然,您可以创建一些对象:例如 RandomGenerator,并使用一些虚函数调用并处理这些不同的行为。但是这段代码应该很快(更新数千个粒子时),所以我认为使用虚函数并不好。

或者也许我不应该关心并简单地写:

foreach p in particles
    p.position = useGaussian ? gausRand() : UniRand()
    p.velocity = useGaussian ? gausRand() : UniRand()

我们可以缩小不同分布的数量,只使用其中的两个或三个......

请注意,我的示例非常简单,但在实际代码中,您有几个粒子参数配置。

我想就该主题获得一些一般性建议。

4

2 回答 2

3

通常在使用 C 的 rand() 函数时,我们会得到均匀分布,但是当我想使用其他分布(例如高斯分布)时怎么办?

Box Muller 变换是一种非常聪明的算法,它使用三角函数从使用均匀分布作为输入(即使用rand())的高斯分布生成随机数。您指定平均值和标准差,并调用此函数来生成新变量。唯一的缺点是它比简单地调用更昂贵rand,因为它还调用sin()and cos()(尽管只有每秒钟调用一次)。

如何更改该代码以使其能够处理几种(或至少两种)不同的方式来生成新粒子的参数?

我建议您从RandomGenerator虚拟方法方法开始。这将是最容易维护的。在尝试优化事物之前,先从最简单的方法和配置文件开始。

鉴于生成随机数的计算复杂性,生成变量的成本将远远超过虚拟方法调用与静态函数调用的开销。

如果这真的,真的不够快,你总是可以生成一个随机数池,根据需要在后台生成更多。

于 2012-06-02T11:06:02.023 回答
3

虽然@gavinb 的答案是一种完全有效的方法,但我建议避免重新发明轮子并使用标准设施:如果您有 c++11 支持,请使用std::normal_distribution及其亲属(参见,例如C++ TR1: how to使用 normal_distribution?)。否则,使用boost::random

由于这些只是标头(至少是 boost 版本),因此不涉及多态调用,因此您不必担心它们。当然,这并不能排除@Oli Charlesworth 建议的最大相关性。

编辑:如果由于多态调用导致的开销不可忽略,您始终可以在枚举类型的分布上模板化您的函数并根据需要对其进行专门化。

简而言之,它就像这样简单:

#include<iostream>

// template on an int selector
template<int N> void foo(){ std::cout<<"42\n"; }
template<> void foo<1>() {std::cout<<"1\n";}

//now use an enum
enum  distr_types {UNIF, NORMAL, UNKNOWN}; 
template<distr_types T> void bar() {std::cout<<"fourty two\n";}
template<> void bar<UNIF>() {std::cout<<"UNIF\n";}
template<> void bar<NORMAL>(){std::cout<<"NORMAL\n";}

int main(){
  foo<3>();
  foo<1>();

  bar<UNIF>();
  bar<NORMAL>();
  bar<UNKNOWN>();
}

但是,如果您发现自己在做这种事情,那么值得一看一本好的 C++ 书籍

于 2012-06-02T11:12:00.243 回答