c++ - 如何让我的递归函数在进入下一级循环之前读取每个新实例?

标签 c++ simulation physics

我必须模拟粒子 split 成粒子。 我的模拟函数决定有多少粒子从 split 中脱落。 然后根据它决定 split 成多少个粒子调用自己进行模拟。

代码如下:

void Reaction::Simulate(double energy,  TwoVector position )
{
    int RandomNumber= qrand() %3+1;//starting particle
    energy = energy/RandomNumber; // change energy for each reaction
    double time=1.0;
    std::cout<<RandomNumber<<std::endl;

    if (RandomNumber==1){
        LightParticle* i=new LightParticle(energy, position);
        int speed = 3;
        i->SimulatePath(time, speed, i->GetPosition());
        i->GetPosition().Print();
        energy--;
        Simulate(energy, i->GetPosition());
    }
    else if (RandomNumber==2){
        MediumParticle* j=new MediumParticle(energy, position);
        MediumParticle* k=new MediumParticle(energy, position);
        int speed = 2;

        j->SimulatePath(time,speed, position);
        k->SimulatePath(time,speed, position);

        j->GetPosition().Print();
        k->GetPosition().Print();

        Simulate(energy, j->GetPosition());
        Simulate(energy, k->GetPosition());
    }
    else if (RandomNumber==3) {
        HeavyParticle* l = new HeavyParticle(energy, position);
        HeavyParticle* m = new HeavyParticle(energy, position);
        HeavyParticle* n = new HeavyParticle(energy, position);
        int speed = 1;

        l->SimulatePath(time,speed, position);
        l->GetPosition().Print();

        m->SimulatePath(time,speed, position);
        m->GetPosition().Print();

        n->SimulatePath(time,speed, position);
        n->GetPosition().Print();

        Simulate(energy, l->GetPosition());
        Simulate(energy, m->GetPosition());
        Simulate(energy, n->GetPosition());
    }
    else return;
}

正如您从代码中看到的那样,在移动到下一条路径之前,它只会到达一条路径的最深层。我怎样才能让它同时遵循每条路径?

最佳答案

首先,这段代码几乎会立即导致堆栈溢出。

您的基本代码路径在伪代码中如下所示:

func() {
    path = RAND(1, 3);
    if(path == 1) /*DO STUFF*/ func();
    else if(path == 2) /*DO STUFF*/ func();
    else /*DO STUFF*/ func();
}

因此,无论这些步骤是否“同时”进行,您的代码都永远不会终止。如果你希望代码最终停止,你应该让随机数在一个范围内,而不是只输出数字 [1, 3]

int RandomNumber= qrand() %4; //Will stop when RandomNumber == 0

如果递归应该停止的时间有更明确的条件(比如当 energy == 0 时),您需要将其写入代码。

您的第二个问题是您不清楚“同时”执行所有这些步骤的意思。您是否希望所有路径在多个线程中并行执行?

你需要这样写:

std::thread t1([=]{
    LightParticle* i=new LightParticle(energy, position);
    int speed = 3;
    i->SimulatePath(time, speed, i->GetPosition());
    i->GetPosition().Print();
    energy--;

    if(condition_to_continue_recursing()) {
        Simulate(energy, i->GetPosition());
    }
});
std::thread t2([=]{
    MediumParticle* j=new MediumParticle(energy, position);
    MediumParticle* k=new MediumParticle(energy, position);
    int speed = 2;

    j->SimulatePath(time,speed, position);
    k->SimulatePath(time,speed, position);

    j->GetPosition().Print();
    k->GetPosition().Print();

    if(condition_to_continue_recursing()) {
        Simulate(energy, j->GetPosition());
        Simulate(energy, k->GetPosition());
    }
});
std::thread t3([=]{
    HeavyParticle* l = new HeavyParticle(energy, position);
    HeavyParticle* m = new HeavyParticle(energy, position);
    HeavyParticle* n = new HeavyParticle(energy, position);
    int speed = 1;

    l->SimulatePath(time,speed, position);
    l->GetPosition().Print();

    m->SimulatePath(time,speed, position);
    m->GetPosition().Print();

    n->SimulatePath(time,speed, position);
    n->GetPosition().Print();

    if(condition_to_continue_recursing()) {
        Simulate(energy, l->GetPosition());
        Simulate(energy, m->GetPosition());
        Simulate(energy, n->GetPosition());
    }
});

t1.join();
t2.join();
t3.join();

但是无论 condition_to_continue_recursing() 是什么,都必须由您决定;我对您的总体任务了解不多,无法回答这个问题。此外,如果您的 condition_to_continue_recursing 非常重要,这将产生荒谬数量的线程;使用线程池可能是首选。所有这一切都取决于您决定使用线程是完成此类任务的理想选择,但(对我而言)这并不明显。

你的第三个问题是这个代码片段中充斥着相当严重的设计错误。

HeavyParticle* l = new HeavyParticle(energy, position);
HeavyParticle* m = new HeavyParticle(energy, position);
HeavyParticle* n = new HeavyParticle(energy, position);

这些指针中的每一个都会泄漏。由于对象仅在定义它们的范围内使用,因此使用 std::unique_ptr 可能是理想的:

std::unique_ptr<HeavyParticle> l = std::make_unique<HeavyParticle>(energy, position);
std::unique_ptr<HeavyParticle> m = std::make_unique<HeavyParticle>(energy, position);
std::unique_ptr<HeavyParticle> n = std::make_unique<HeavyParticle>(energy, position);

编辑:或者,您一开始就应该在这种情况下使用指针并没有充分的理由。以下代码可以完美运行,没有内存泄漏或更改代码的功能:

HeavyParticle l(energy, position);
HeavyParticle m(energy, position);
HeavyParticle n(energy, position);
int speed = 1;

l.SimulatePath(time,speed, position);
l.GetPosition().Print();

m.SimulatePath(time,speed, position);
m.GetPosition().Print();

n.SimulatePath(time,speed, position);
n.GetPosition().Print();

Simulate(energy, l.GetPosition());
Simulate(energy, m.GetPosition());
Simulate(energy, n.GetPosition());

您可能也不应该使用 qrand

std::default_random_engine engine(std::random_device()());

void Reaction::Simulate(double energy,  TwoVector position )
{
    std::uniform_int_distribution<int> distribution(0, 3);
    int RandomNumber = distribution(engine);
    /*... Whatever*/

更好的设计会将引擎传递给函数。

备选方案:

std::default_random_engine engine(std::random_device()());

void Reaction::Simulate(double energy,  TwoVector position )
{
    if(energy <= 0) return;
    std::uniform_int_distribution<int> distribution(1, 3);
    int RandomNumber = distribution(engine);
    /*... Whatever*/

还有很多内容,但还有很多内容需要深入挖掘。希望这将提供一个良好的起点。

关于c++ - 如何让我的递归函数在进入下一级循环之前读取每个新实例?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41577469/

相关文章:

javascript - 模拟类似于尘埃粒子的运动

r - 以自定义分布为条件模拟向量

Python:在字典中存储设置与 argparse.Namespace

iphone - 如何使用 Cocos2d 来创建一款这样的游戏

C++:洛伦兹因子方程

r - 为什么 rmvnorm() 函数返回 "In sqrt(ev$values) : NaNs produced",这个错误是什么以及如何纠正或避免它?

C++ 将隐藏的 arg 传递给类构造函数?

c++ - 如果枚举不能适合无符号整数类型会发生什么?

c++ - 多次解包参数包

c++ - 从 'char' 到 'const char*' 的无效转换 [-fpermissive]