2017-01-10 3 views
0

Ich muss Partikel in Partikel zerlegen simulieren. Meine Simulationsfunktion legt fest, wie viele Partikel aus dem Split herauskommen. Dann ruft sich selbst zu simulieren, abhängig davon, wie viele Partikel es sich aufgeteilt hat.Wie mache ich meine rekursive Funktion lesen jede neue Instanz, bevor Sie auf die nächste Stufe der Schleife?

Hier ist der Code:

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

Wie Sie aus dem Code sehen können, es nur auf der tiefsten Ebene des einen Weg geht, bevor zum nächsten zu bewegen. Wie kann ich es jedem Pfad gleichzeitig folgen lassen?

+1

Für zukünftige Fragen stellen Sie bitte sicher, dass Ihr Code richtig formatiert ist. Unsachgemäß formatierter Code ist extrem schwierig zu analysieren und daher extrem schwer zu debuggen. – Xirema

+0

wow das sieht so viel besser aus, danke –

+3

Vielleicht wäre es besser, alle Partikel in einer Struktur darzustellen, wie zum Beispiel 'std :: vector', dann führe' Simulate' auf allen dann für eine einzelne Iteration aus und wiederhole es so oft wie Sie es für notwendig halten. Vermeiden Sie "neu". Mit einem Vektor verwenden Sie einfach 'push_back', um jedes neue Partikel hinzuzufügen. – wally

Antwort

4

Zuerst werden Sie fast sofortige Stapelüberläufe mit diesem Code erhalten.

Ihre grundlegende Codepfad sieht wie folgt aus, in Pseudo-Code:

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

Also unabhängig davon, ob diese Schritte „gleichzeitig“ oder nicht, Ihren Code nie sowieso beendet. Wenn Sie möchten, dass der Code schließlich beendet wird, sollten Sie die Zufallszahl in einem Bereich haben, in dem nicht nur die Zahlen [1, 3] ausgegeben werden.

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

Wenn es eine explizitere Bedingung für, wenn die Rekursion stoppen soll (wie wenn energy == 0), müssen Sie das in anstatt codieren.

Ihr zweites Problem ist, dass es nicht klar ist, was Sie meinen, indem Sie alle diese Schritte "gleichzeitig" ausführen. Erwarten Sie, dass alle Pfade parallel in mehreren Threads ausgeführt werden?

Sie werden so etwas schreiben müssen:

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(); 

Aber was auch immer condition_to_continue_recursing() ist, wird von Ihnen entschieden werden müssen; Ich weiß nicht genug über Ihre allgemeine Aufgabe, dies zu beantworten. Auch das wird eine absurde Anzahl von Threads hervorbringen, wenn Ihr condition_to_continue_recursing ziemlich wichtig ist; Die Verwendung eines Thread-Pools könnte bevorzugt werden. Und all das hängt davon ab, dass Sie entscheiden, dass die Verwendung von Threads für diese Art von Aufgabe ideal ist, was für mich nicht offensichtlich ist.

Ihr drittes Problem ist, dass dieses Code-Snippet mit ziemlich signifikanten Entwurfsfehlern übersät ist.

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

Jeder dieser Zeiger wird undicht. Da die Objekte nur im Rahmen verwendet werden, in der sie definiert habe, die Verwendung von std::unique_ptr ist wahrscheinlich ideal:

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

EDIT: Alternativ gibt es keinen wirklichen Grund ist, warum sollten Sie Zeiger in diese verwenden Kontext in erster Linie. Der folgende Code würde perfekt funktionieren ohne Speicherlecks in Ordnung oder auf die Funktionalität des Codes ändern:

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()); 

Sie sollten auch wahrscheinlich nicht qrand verwendet werden.

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

Ein besseres Design würde den Motor in die Funktion übergeben.

Alternative:

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

Es gibt eine Menge mehr dazu, aber es gibt eine Menge zu graben in. Hoffentlich wird dies einen guten Ausgangspunkt geben.

+1

Sehen Sie einen Grund, Zeiger anstelle der Objekte selbst zu verwenden? Für das vorgestellte Schnipsel ist nicht "Particle i (Energie, Position)", genauso gut? Dann lass den Destruktor alles aufräumen. Große Antwort übrigens. – Matt

+0

Ein guter Grund könnte sein, dass '* Particle'-Objekte extrem schwer/groß sind, was Stapelüberlaufprobleme einfach durch Zuordnen von zu vielen von ihnen auf dem Stapel riskieren könnte. Zugegeben, das ist ein extremer Fall, und ich bezweifle, dass es ein Problem für den hier abgetasteten Code ist, aber an einem bestimmten Punkt auf diesem Pfad haben wir aufgehört zu sagen "Hier sind die konkreten Probleme mit deinem Code" und haben angefangen zu sagen: Okay, ich werde das komplett umschreiben, so wie ich es getan hätte ", was eine größere Ausgabe meiner Zeit ist. = D – Xirema

+0

Etwa so gut eine Antwort wie die Frage in ihrem Zustand bekommen kann. Ein Fall kann gemacht werden, um die zugewiesenen Partikel in einer Baumstruktur zu speichern, die Wurzel zurückzugeben und dann durch den Baum zu iterieren, um die Ergebnisse zu verarbeiten, bevor sie schließlich zerstört werden.Der Baum kann dazu gebracht werden, * gleichzeitig * mit einer Breite-zuerst-Traversierung in einem einzelnen Thread * zu schauen und gleichzeitig das Speicherleck zu handhaben. – user4581301

0

Der qsrand() behält immer den gleichen Wert, wenn er nicht mit einem Wert initialisiert wird.

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

oder

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

Aufgrund eines Mangels an MCVE wissen wir nicht, ob Raket Makhim die Rng ausgesät hat oder nicht. – user4581301

+0

Ja, ich habe das auf die harte Tour gelernt. Aber habe es jetzt ausgesät. Danke für die Antwort! –

0

Ich weiß nicht, ob Sie wirklich alle Wege gleichzeitig folgen wollen. Meiner Meinung nach geht es darum, die Schleife zu durchbrechen. Dies sollte wie

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

zur Verfügung gestellt werden, in dem Sie eine Funktion bool isAtGround(const TwoVector& position) und ein minimalEnergy wenn Ihre Partikel nicht weiter teilen (typische Grenzen die leichtesten Teilchen Massen) bieten sollten. Es könnte sein, dass du, statt zurück zu kehren, wenn die Energie zu klein ist, dem Partikelpfad zum Boden folgen könntest. Aber das hängt von Ihrer konkreten Aufgabe ab.

Übrigens scheint es mir komisch, dass die Energie nur für RandomNumber==1 gesenkt wird.

+0

Ja, ich hatte Schwierigkeiten, die Schleife zu brechen. Ich habe ein if (Energie> 4) vor dem ganzen Code und dachte, dass das aufhören würde, Partikel zu simulieren. Die Energie wird nur um 1 gesenkt, weil bei 2 und 3 die Energie gleichmäßig unter den neuen Teilchen aufgeteilt wird. Danke für Ihre Antwort –

Verwandte Themen