2017-01-10 52 views
0

我必須模擬粒子分裂成粒子。 我的模擬功能決定從分割中有多少粒子脫落。 然後調用它自己來模擬它取決於它決定分割成多少粒子。在繼續下一級循環之前,如何讓遞歸函數讀取每個新實例?

下面的代碼:

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; 
} 

正如你可以從代碼中看到,那就只一個路徑的最深層次移動到下一個前。我怎樣才能使它沿着每條路徑同時進行?

+1

對於將來的問題,請確保您的代碼格式正確。格式不正確的代碼非常難以分析,因此極難調試。 – Xirema

+0

哇,看上去好多了,謝謝 –

+3

也許最好是代表一個結構中的所有粒子,比如'std :: vector',然後在一次迭代中運行'Simulate',然後重複多次因爲你認爲有必要。避免'新'。使用vector可以使用'push_back'來添加每個新粒子。 – wally

回答

4

首先,你會得到這個代碼幾乎即時堆棧溢出。

你的代碼路徑基本是這樣,在僞代碼:

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*/ 

還有很多更多的這個,但是有很多鑽進去。希望這會給出一個好的起點。

+1

您是否看到使用指針而不是對象本身的理由?所呈現的片段不是「粒子我(能量,位置)」,「同樣好?然後讓析構函數清理一切。很好的答案。 – Matt

+0

一個很好的原因可能是如果'* Particle'對象非常重/大,這可能會導致堆棧溢出問題,只需在堆棧中分配太多堆棧溢出問題。當然,這是一個極端的情況,我懷疑這是在這裏採樣的代碼的問題,但是在這個路徑的某個點上,我們不再說「這裏是你的代碼的具體問題」,並開始說「好吧,我會徹底改寫這種方式*我*會做到這一點「,這是我的時間花費更大。 = D – Xirema

+0

關於這個問題可以得到它的狀態的一個很好的答案。可以將分配的粒子存儲在樹結構中,返回根,然後遍歷樹來處理結果,然後最終銷燬結果。可以使樹看起來與單線程中的寬度優先遍歷同時處理內存泄漏。 – user4581301

0

當未用值初始化時,qsrand()將始終保持相同的值。

qsrand(time(NULL)); 
ID=qrand() % 3; 
qDebug << 「ID random: 「 << ID; 

qsrand(static_cast<quint64>(QTime::currentTime().msecsSinceStartOfDay())); 
array<int, 3> arr = {qrand(), qrand(), qrand()}; 
for(auto i : arr) 
    cout << i << endl; 
+3

由於缺乏MCVE,我們不知道Raket Makhim是否接種了rng。 – user4581301

+0

是的,我確實瞭解到這一點。但現在播種了。 感謝您的回覆! –

0

我不知道你是否真的要同時遵守所有的路徑。在我看來,麻煩在於打破循環。這應該是提供像

void Reaction::Simulate(double energy, TwoVector position) 
{ 
    if (energy < minimalEnergy) return; 
    if (isAtGround(position)) return; 

    int RandomNumber= qrand() %3+1;//starting particle 
    // all the rest, but please repair the memory leaks! 
} 

,你應該提供一個功能bool isAtGround(const TwoVector& position)minimalEnergy當你的粒子無法進一步劃分(典型的限制是最輕的粒子質量)。如果能量太小,它可能不是返回,而是沿着粒子路徑到達地面。但這取決於你的具體任務。

順便說一下,我覺得能量只降低了RandomNumber==1

+0

是的,我很難讓循環休息。在所有的代碼之前我有一個if(能量> 4),並且認爲它會停止模擬粒子。能量僅降爲1,因爲在2和3時,能量在新粒子中平均分配。 感謝您的回覆 –

相關問題