C++ 如何有效地处理不同的概率分布函数?

C++ 如何有效地处理不同的概率分布函数?,c++,optimization,graphics,particle-system,C++,Optimization,Graphics,Particle System,我有一个粒子系统,通常会创建新粒子,更新它们并销毁 在发射器模块中,有用于重置粒子的for循环: foreach p in particles p.position = rand() p.velocity = rand() 通常,当使用C的rand()函数时,我们会得到均匀分布,但当我想使用其他分布(例如高斯分布)时,会怎样呢 如何更改该代码,使其能够处理生成新粒子参数的几种(或至少两种)不同方式 当然,您可以创建一些对象:比如RandomGenerator,使用一些虚拟函数调

我有一个粒子系统,通常会创建新粒子,更新它们并销毁

在发射器模块中,有用于重置粒子的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()
我们可以缩小不同分布的数量,只使用其中的两个或三个

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

我想在这个问题上得到一些一般性的建议

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

这是一个非常聪明的算法,它使用trig函数从高斯分布生成随机数,使用均匀分布作为输入(即使用
rand()
)。指定平均值和标准偏差,并调用此函数生成新变量。唯一的缺点是,它比简单地调用
rand
要昂贵,因为它还调用
sin()
cos()
(尽管只需每秒调用一次)

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

我建议您从随机生成器和虚拟方法开始。这将是最容易维护的。在尝试优化之前,先从最简单的方法和概要开始

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

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

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

这是一个非常聪明的算法,它使用trig函数从高斯分布生成随机数,使用均匀分布作为输入(即使用
rand()
)。指定平均值和标准偏差,并调用此函数生成新变量。唯一的缺点是,它比简单地调用
rand
要昂贵,因为它还调用
sin()
cos()
(尽管只需每秒调用一次)

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

我建议您从随机生成器和虚拟方法开始。这将是最容易维护的。在尝试优化之前,先从最简单的方法和概要开始

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


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

虽然@gavinb的答案是一个非常有效的方法,但我建议避免重新发明轮子,使用标准工具:如果你有c++11支持,使用
std::normal_distribution
及其亲属(参见,例如)。否则,请使用

因为这些都是只包含头的(至少是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>();
}
#包括
//int选择器上的模板

模板void foo(){std::cout虽然@gavinb的答案是一个非常有效的方法,但我建议避免重新发明轮子,使用标准工具:如果您有c++11支持,请使用
std::normal_distribution
及其相关函数(参见,例如)。否则,请使用

由于这些只是标题(至少是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>();
}
#包括
//int选择器上的模板

模板void foo(){std::您是否分析了这段代码以确定虚拟调用开销是一个问题?我没有分析,但我想了解一些关于这种情况的一般想法。我认为,当存在数千个粒子时,虚拟方法调用确实很重要。一般的想法是,在分析确定某些问题之前,您不应该进行优化o可能是个问题。@fen:不太可能。如果你以每秒3000次的速度重新分发它们,比如说。你分析过这段代码以确定虚拟呼叫开销是个问题吗?我没有分析,但我想得到一些关于这种情况的一般想法。当有数千个particle