Sonnensystem: Position der Planeten?

Bernhard

Registriertes Mitglied
Worin ich Dich gern bestärken möchte: Plane Deine Schritte. Mach bitte einen Schritt nach dem Anderen. Mach kleine Schritte, diese dann allerdings vollständig. Und geh danach erst weiter bis zum Ende.
Hi Rübe,

man kann prinzipiell aber auch aus Fehlern lernen. Meine Devise lautet in diesem Fall deswegen: Lieber ein paar Fehler machen, als gar nix machen.

Dass .NET soviel besser ist, als Altbekanntes muss mir .NET erst mal beweisen.
Gruß
 

Runzelrübe

Registriertes Mitglied
Hi Bernhard,

Dass .NET soviel besser ist, als Altbekanntes muss mir .NET erst mal beweisen.

Erklär mir bitte: hattest Du wirklich vor, das Thema mit diesem Kommentar jetzt in eine bestimmte Richtung (die arg nach einer Diskussion PC vs. MAC aussieht) zu lenken? Was meinst Du denn mit altbekannt? Und wieso ist das Altbekannte denn so viel besser? Weil Du es kennst? Ja, der Mensch ist schon ein faules Tier. Was macht das Altbekannte denn besser? Kleiner Tipp: altbekannt bedeutet zuerst mal, dass es früher dagewesen ist, nicht automatisch, dass es das beste ist, was es je geben wird. Es gab auch eine Evolution der Computersprachen. Die Erde war lange Zeit eine Scheibe, das war auch altbekannt, hatte aber ein paar Makel. Dann war sie kugelförmig, dann doch eher ein Geoid. Hey, hat sich doch gelohnt. Niemand wird mehr daherkommen und behaupten, sie wäre eckig. Und uns allerliebster Newton war auch zuerst da, doch dann kam Einstein. :rolleyes:

Daher: denkt bitte nicht, dass irgendeine x-beliebige Programmiersprache einer anderen überlegen ist, denn sie ist auch nur eine weitere x-beliebige Krücke zur Binärwelt. Ja komm, ich kenn euch: es ist so schön bequem, sich zurückzulehnen, wenn man eine Sprache endlich beherrscht. :D Manche dieser Binärkrücken sind sicher, manche hübsch, manche einfach, manche für Anfänger, manche nicht kompatibel zum Problem usw.

Aber: wenn ich lese, dass ein Programm, das in Hochsprache A geschrieben wurde, in Hochsprache B konvertiert wird, damit dies und das funktioniert, obwohl dies (fremd-)wissentlich nicht notwendig wäre, dann klingeln bei mir die Alarmglocken und ich schreite zur Tat.

Ich stimme Dir im Übrigen im Grundsatz zu, den Ansporn zu haben, aus Fehlern zu lernen. Das ist meiner Meinung nach fundamental richtig. Doch dazu gehört eben auch, die Fehler zu erkennen oder darauf aufmerksam gemacht zu werden. Und da liegt der Hase im Pfeffer. Man hat es so schön einfach, wegzuschauen.

Fehler zu wiederholen, führt zu noch mehr Fehlern. Und ohne qualifizierte Tests wird das nix. Diese fangen aber leider ganz unten an, beim Urschleim, dem ollen blöden Rechner mit seinen ollen blöden Registern, die nur gesagt bekommen, was sie wann zu tun haben. Schieb mal das hierher und dann dreh Dich im Kreis. Toll!

Gegenfrage: Führst Du mathematische Korrekturterme ein, damit die Messwerte stimmen, damit sie Dir der erstbeste Kollege später um die Ohren haut? Und zwar obwohl Dir gesagt wurde, dass diese Korrekturterme ein no-go sind? Manchmal muss man eben zwischendurch nochmal sein Wissen aufbessern oder nachhaken. War das denn jetzt wirklich so schlimm, das zu erwähnen? Oder worin liegt da das Problem, Deiner Meinung nach? Weil ich nicht ja und Amen dazu sage, dass SRMeister sich Mühe gibt? Hey, ich teile mein Wissen freiwillig, weil ich ihm damit helfen möchte. Das ist verdammt nochmal viel wert!

LG,
Runzel
 
Zuletzt bearbeitet:

SRMeister

Registriertes Mitglied
Hallo,

GPUs arbeiten jedoch mit noch geringeren Bit-Breiten für Datentypen.
soweit ich weis stimmt das zumindest im Fall Cuda nicht, wenn man die ersten Cudafähigen Baureihen ausklammert.
wikipedia schrieb:
Zur Verbesserung der GPU-Computing-Fähigkeiten verfügen die Grafikprozessoren der „Fermi-Architektur“ als erste überhaupt über eine komplette Unterstützung von C++ und sind, genau wie die Radeon-HD-5000-Serie von AMD, mit dem IEEE-754-2008-Standard vollständig kompatibel.

Da ich ebenfalls in .NET entwickle, sei Dir noch ans Herz gelegt, Dich zum Thema unmanaged lieber in Richtung Marshalling zu informieren.
Genau so ist es natürlich geplant. Ich hab im Moment ne c++ Konsolenanwendung und ne .NET Win Anwendung und die sollen zusammengeführt werden. Leider mach ich das auch das erste mal deswegen haperts etwas mit der Umsetzung. Stichwort: Wrapper Klasse erstellen. Habe ja nicht gewusst dass es noch andere .net nerds hier gibt :)
PS wie schon gesagt würde mich über jede Hilfe freuen :)

Sei bitte vorsichtig, sowohl mit Deinen Datentypen und auch mit Deiner Speicherverwaltung.
immer!

Meine Ergebnisse waren nett anzuschauen, aber leider komplett unbrauchbar. Und das hat mich eher enttäuscht als motiviert.
Warum waren sie unbrauchbar?

Ich kann Dir nur raten, red Dir nicht ein, Ratschläge selektiv zu ignorieren, weil Du das ja nur aus Hobby machst. Du könntest sonst am Ende ebenfalls enttäuscht sein, wenn Du das Programm präsentierst und es nur für 10-Körper-Probleme ähnlicher Größenordnungen gut läuft.
Natürlich denke ich über jeden gemachten Ratschlag nach. Es gibt in meinem Kopf eine ToDo Liste wozu bspw. auch die Durcharbeitung des verlinkten Textes über Fehlerfortpflanzung gehört und die Beschäftigung mit dem Fehler sowieso. Nur muss ich erst sehen ob ich das Programm ansich überhaupt soweit bekomme, dass es überhaupt Ergebnisse liefern kann. Es kann ja auch sein, dass bei 10 Körpern das Programm so langsam wird dass ich aufgebe. Dann wäre alle jetzige Mühe zum Thema Fehler verschwendet.

Dass .NET soviel besser ist, als Altbekanntes muss mir .NET erst mal beweisen.
Ich hab auch mit MFC angefangen. Aber ehrlich gesagt würd ich jetzt nie wieder freiwillig zu MFC zurückkehren. Und C++ wird nurnoch gemacht wenns nötig ist, wie hier.
NET ist vielleicht nich allgemein besser, dafür aber auf jeden Fall, nimmt es einem sehr viel arbeit ab, gerade im Bereich Windows Programmierung, aber eigentlich auf allen Gebieten.

Stefan
 

FrankSpecht

Registriertes Mitglied
Moin, Runzel,
hattest Du wirklich vor, das Thema mit diesem Kommentar jetzt in eine bestimmte Richtung (die arg nach einer Diskussion PC vs. MAC aussieht) zu lenken?
Ich glaube nicht. Ich denke, Bernhard geht es hauptsächlich um das .NET.
Ist halt Microsoft-spezifisch und nicht ohne weiteres kompatibel zu Standard-C (oder C++), so dass ein solches Programm ohne Aufwand nicht auch auf anderen Betriebssystemen lauffähig ist.

Außerdem geht es um die Ausführungsgeschwindigkeit, die ja, je nach Aufgabe, auch eine Rolle spielen könnte:
http://de.wikipedia.org/wiki/.NET schrieb:
Damit entfernt sich die Softwareentwicklung, insbesondere die Anwendungsentwicklung, insgesamt von dem Augenmerk auf Ausführungsgeschwindigkeit, die angesichts einer immer schneller werdenden Rechengeschwindigkeit zunehmend in den Hintergrund rückt.
 

Bernhard

Registriertes Mitglied
hattest Du wirklich vor, das Thema mit diesem Kommentar jetzt in eine bestimmte Richtung (die arg nach einer Diskussion PC vs. MAC aussieht) zu lenken?
Hi RR,

mir ging es eigentlich nur darum SRMeisters lobenswerte Motivation vor überzogenen Software- und Codierungsrichtlinien zu schützen.
Gruß
 

Bernhard

Registriertes Mitglied
Ich hab auch mit MFC angefangen. Aber ehrlich gesagt würd ich jetzt nie wieder freiwillig zu MFC zurückkehren. Und C++ wird nurnoch gemacht wenns nötig ist, wie hier.
Hi Stefan,

vielen Dank für den Tip, aber um mal wieder auf die Physik und Numerik zurück zukommen: Mit welchem Verfahren machst, bzw. willst Du eigentlich die Integration implementieren und in welchen Koordinaten rechnest Du? Ich könnte mir vorstellen, dass man in Kugelkoordinaten schon mal weiter kommt, als in euklidischen Koordinaten.
Gruß
 
Zuletzt bearbeitet:

Bernhard

Registriertes Mitglied
3. Du rechnest den neuen Geschwindigkeitsvektor mit dem hiesigen Beschleunigungsvektor aus, läßt sie aber einen halben Tag lang mit dem alten Geschwindigkeitsvektor bewegen und den zweiten halben Tag mit dem neuen Geschwindigkeitsvektor. (Man kann das nach diesem Startschritt bei den folgenden Schritten auch geeignet zusammenfassen)
Hi MAC/Stefan,

eine Beschreibung dieses Verfahrens findet man u.a. auch hier: http://en.wikipedia.org/wiki/Midpoint_method.
Gruß
 

Runzelrübe

Registriertes Mitglied
Hi Stefan,

die Einschränkung auf CUDA ist ähnlich bindend wie eine Sprache, mit dem Unterschied, dass zwangsläufig auch noch NVidia Hardware vorausgesetzt wird. Und dass CUDA jetzt endlich auch Double Precision kann, das war mir neu. Aber auch NVidia schläft eben nicht. :)

Zu Deinen Bedenken bezüglich Geschwindigkeit. Auf meinem damaligen AMD Athlon 2100+ liefen sowohl die Berechnung als auch 3D-Darstellung eines 60-Körper-Systems wie ein Echtzeitvideo. Einzig für die Simulation von 2500-Körper-Systemen habe ich eine Videoauslagerung integriert und meinen Rechner nachts arbeiten lassen.

Warum waren sie unbrauchbar?

Weil mir damals einige Parameter als vernachlässigbar klein erschienen. Sonnenwind und Gezeitenkräfte hatten meines Erachtens viel zu geringe Auswirkungen. Ich hatte die Auswirkungen naher Vorübergänge einfach aus Bequemlichkeit nichtmal durchgerechnet. Dazu kommt, dass die Ausbreitungsgeschwindigkeit der Gravitation bei mir instantan erfolgte, statt mit Lichtgeschwindigkeit. Ich benötigte immer ein schweres schwarzes Loch im Zentrum zur Stabilisierung eines Kugelsternhaufens. Das seltene Ereignis einer Nahbegegnung eines Sterns mit diesem hatte dann regelmäßig das Ende der schön anzusehenden Simulation zur Folge. Denn auch die Annihilation eines Sterns (und sei es nur durch einen unelastischen Stoß) hatte ich weggelassen. Ganz am Ende habe ich mir einfach gesagt, dass es ja ganz nett aussieht und habe mich anderen Dingen gewidmet. Einige Jahre später wusste ich dann besser Bescheid, habe mich nur leider nie wieder rangesetzt. Bei einem Thema konnte ich mir jedoch 100%ig sicher sein. Dass die verwendeten Datentypen mich nicht im Stich lassen konnten. Such mal nach Jonathan Richard Shewchuk. Prioritäten liegen eben bei jeder Person woanders. Das macht uns so schön unterschiedlich. :)

Schönes Beispiel zum Nachdenken:

(333.75−a^2)*b^6+a^2*(11*a^2*b^2−121*b^4−2)+5.5*b^8+a/(2*b)

a = 77617
b = 33096

Ergebnisse:

32-bit: 1.172604
64-bit: 1.1726039400531786
128-bit: 1.1726039400531786318588349045201838

Wie auch immer, das richtige Ergebnis lautet: −0.8273960.

-----------

Hi Bernhard,

mir ging es eigentlich nur darum SRMeisters lobenswerte Motivation vor überzogenen Software- und Codierungsrichtlinien zu schützen.

Fremdschutz ist sinnvoll, wenn derjenige, den es zu schützen gilt, bevormundet werden möchte oder diese Aufgabe jemandem übertragen hat. Mir kam es aber zumindest so vor, als wisse Stefan bereits, dass ich nicht gegen ihn argumentiere, sondern auf Fehlerquellen hinweise. Sein Programm kann definitiv auch mit Double Precision Berechnungen gute Ergebnisse liefern. Und wie er bereits schrieb, möchte er sich die Links später noch zu Gemüte führen.
 
Zuletzt bearbeitet:

SRMeister

Registriertes Mitglied
so es geht weiter.

Ich habe nun eine normale C++ Konsolenversion gemacht und ihr dürft sie gerne zerpflücken - aber hoffentlich auch beim Verbessern helfen :D

Im Moment läuft das ganze so:
Euler Methode (Keine Zwischenpunktberechnung), Zeitschritt eine Sekunde, innere Planeten bis Erde plus Mond,
im angehängten Beispiel werden etwa 2 Monate integriert. Die Position stimmt mit der von NASA folgendermaßen nicht überein :

X Abweichung 24.500km, Z Abweichung 1800km, Y irgendwo darunter...
Nur als Referenz die Erde hat sich in der Zwischenzeit "Luftlinie" folgende Strecke bewegt:
X 870 Mio km, Y 110 Mio km, Z 4 Mio km

Der Fehler ist also erstmal "recht gering", vielleicht durch die fehlenden äußeren Planeten oder durch die Ungenauigkeit der Methode.

Der nächste Schritt ist der Wechsel weg von der Euler Methode hin zu was genauerem.
Wahrscheinlich erstmal die Midpoint Methode.
Danach wird das Ganze als DLL kompiliert und wieder in .NET eingebunden damit die Grafikmöglichkeiten wieder da sind.

Was mich interessieren würde: Wenn ich die Genauigkeit steigere, bspw. durch wechsel Euler -> Midpoint, verdoppelt sich die Rechenzeit. Das lohnt sich ja nur wenn die Genauigkeit mehr steigt als Faktor 2 damit ich die Schrittweite größer machen kann. Es gibt ja dann noch mehr Methoden (Runge-Kutta-Methoden). Allerdings muss es ja irgendwo ne Grenze geben, wo die Genauigkeit sich zum Rechenaufwand sich nicht mehr verbessert ??

hier für jeden zum Nachschauen.
Inklusive EXE Datei für alle die zu faul sind sich Visual Studio Express (kostenlos) zu saugen, oder keine Ahnung vom Programmieren haben :)

schönen Abend!
Stefan
 

Bernhard

Registriertes Mitglied
Ich habe nun eine normale C++ Konsolenversion gemacht und ihr dürft sie gerne zerpflücken - aber hoffentlich auch beim Verbessern helfen :D
Hi Stefan,

ich hatte oben leider etwas Panik bekommen, dass du deine Ankündigung einer Veröffentlichung von Code wieder fallen läßt. Deswegen erst mal vielen Dank für den Code. Vorallem auch deswegen, weil ich viele Jahre mit Visual C++ 6.0 vor allem beruflich gearbeitet habe und neulich mit ziemlichem Schrecken festgestellt habe, dass Visual C++ 2010 doch sehr viele Änderungen mit sich bringt. Der Hinweis auf unmanaged code war deswegen für mich eine mittlere Erlösung von unüberwindlich erscheindenden Migrationsproblemen.

Zusammen mit Internet und diversen Büchern werde ich mich jetzt erst mal in die Problematik einarbeiten, alte Programme fit für Windows7 zu machen.

Zu Deinem Programm kann ich nur sagen, dass viele Wege nach Rom führen und ich kann nur sehr empfehlen bei vorhandener Zeit auch mehrere Wege auszuprobieren. Man kann dann Ergebnisse bezüglich der Genauigkeit vergleichen. Der Genauigkeit wird in der Praxis zumindest in meinem Umfeld nicht selten der Vorzug gegeben im Vergleich zur Rechenzeit.
Gruß
 

SRMeister

Registriertes Mitglied
Hey Bernhard,
ja mit VS6 hab ich auch angefangen. Um ehrlich zu sein hab ich auch ewig damit gearbeitet, noch als es schon längst VS2003.NET gab.
Das Projekt jetzt lässt bei mir auch teilweise gute Erinnerungen an die alten Zeiten aufleben, hab lange nix in unmanaged C++ gemacht.
Das jetzige Projekt wurde mit VS2008 erstellt, allerdings kannst du ganz einfach mit jedem beliebigen C++ Compiler ein Projekt erstellen mithilfe der paar Quellcode Dateien. Einzig die 2 standart-includes in main.cpp müsste man evtl. anpassen.

hier noch eine kleine Geschwindigkeitsverbesserung:

in der Datei PSystem.cpp, die Funktion DoStep, dort der Inhalt der if-Anweisung kann durch folgendes ersetzt werden. Bringt etwa 30% speed:
PHP:
PVektor *tmp = PVektor::Sub(target->pos, source->pos); // Beschleunigung berechnen
double dist = tmp->Len();
tmp->Mul(target->mass/(dist*dist*dist));
source->Accel->Add(tmp); // Beschleunigung hinzufügen
delete tmp;

(Endlich bringt die Code Funktion hier mal was :D)
Übrigens dauern bei mir die 2 Monate etwa 14 sec auf 2,4 Ghz Intel Core 2 Prozessor, ich finde das ist recht schnell und wenn ich bei der ungefähren Geschwindigkeit bleibe und die Genauigkeit weiter steigern kann, kann ich denke mit dem NASA Horizons hoffentlich mal mithalten :)
Ziel wie gesagt, höchste Genauigkeit, Integration über 100 Jahre, Berechnung des inneren Sonnensystems inkl. einiger NEAs.

CUDA verschiebe ich erstmal, ist mir noch etwas zu weit entfernt (im Sinne von ich hab einfach zuwenig Ahnung davon) aber SSE2 ist noch ne alternative. Mal schauen.
Erstmal möchte ich aber die Midpoint Methode haben! Hoffe da noch auf Unterstützung, Codebeispiele oder ähnliches!

Stefan
 

Bernhard

Registriertes Mitglied
Erstmal möchte ich aber die Midpoint Methode haben! Hoffe da noch auf Unterstützung, Codebeispiele oder ähnliches!
hier mal ein kleiner Code-Review:

a) Tippfehler in main.cpp, Zeile 57: Starzeit -> Startzeit

b) PSystem.cpp, Zeile 86: Die Deklarationen
PHP:
PVektor *tmp
und
PHP:
double dist
würde ich aus sämtlichen Schleifen herausziehen und an den Anfang der Funktion stellen. Zeile 92 kann man dann weglassen, weil der Speicher für die Variable beim Verlassen der Funktion automatisch freigegeben wird. Mag sein, dass der Compiler das eh so übersetzt, aber damit wird der Code auch übersichtlicher und lesbarer.

Insgesamt würde ich auch aus Gründen der Rechengeschwindigkeit unter dem if also eher den folgenden Code verwenden:
PHP:
tmp = PVektor::Sub(target->pos, source->pos); // Beschleunigung berechnen
dist = tmp->Len();
tmp->Mul(Gconst*target->mass/(dist*dist*dist));
source->Accel->Add(tmp); // Beschleunigung hinzufügen

Damit hat man dann die Beschleunigung in SI-Einheiten. Die Gravitationskonstante Gconst sollte IMO nur an dieser Stelle in die Rechnung einfließen. Zeile 94 würde ich rausnehmen und in die Funktion Planet::Move einbauen, damit die Variablennamen auch wirklich das bezeichnen, was sie speichern. D.h. die Variable accel sollte nur Beschleunigungen und keine Positionen speichern.

Der Funktion Move würde ich deshalb die Schrittweit als Parameter übergeben und den Code in der Funktion wie folgt anpassen:
PHP:
Velocity->Add(Accel * schrittweite);
pos->Add(Velocity * schrittweite);
Accel->Reset();

Man kann dann das Projekt als Ganzes kopieren und in der Methode Move die Midpoint-Methode implementieren. Eventuell sollte man die Methode Move auch umbenennen. Wie wäre es z.B. mit Planet::GetNextPosition(double schrittweite)?

c) Bei der Klasse Planet fehlt mir noch der Destruktor, der den mit new reservierten Speicher für die Vektoren pos, Accel und Velocity wieder freigibt.
Gruß
 
Zuletzt bearbeitet:

SRMeister

Registriertes Mitglied
Zeile 92 kann man dann weglassen, weil der Speicher für die Variable beim Verlassen der Funktion automatisch freigegeben wird. Mag sein, dass der Compiler das eh so übersetzt, aber damit wird der Code auch übersichtlicher und lesbarer.
Das ist in dem Fall nicht korrekt da es sich um Zeiger handelt und auch wenn die Zeigervariable selbst gelöscht wird so bleibt der Inhalt des Speichers erhalten, weshalb ein delete erforderlich ist.

Alle anderen vorgeschlagenen Sachen sind mMn korrekt und deshalb umgesetzt.

Die Gravitationskonstante Gconst sollte IMO nur an dieser Stelle in die Rechnung einfließen.
Aus Gründen der "mathematischen Correctness" wäre das richtig, aber da bei dieser Variante die Gconst mit multipliziert werden muss, hab ich sie gleich beim Festlegen der Masse einbezogen. So spart man sich die eine Multiplikation dort wo es auf speed ankommt.

Zeile 94 würde ich rausnehmen und in die Funktion Planet::Move einbauen, damit die Variablennamen auch wirklich das bezeichnen, was sie speichern. D.h. die Variable accel sollte nur Beschleunigungen und keine Positionen speichern.
PHP:
source->Accel->Mul(TconstSquare); // Pos = Zeit*Zeit*Kraft
ist meiner Meinung nach korret. Folgendermaßen:
Ich habe ja weiter vorne erwähnt dass ich Quasi rausgefunden habe: Normalerweise berechnet man die Kraft auf einen Körper. Diese Kraft ist aber auf den anderen genau gleich groß, deshalb spart man sich an der Stelle eine Berechnung. F(hin) = F(zurück).
Das habe ich also folgendermaßen umgesetzt, indem ich überhaupt die Kraft garnicht erst berechne, sondern für jeden Körper die Beschleunigung. Die beiden Varianten sind zwei Seiten derselben Medaille, denn: berechne ich zunächst die für beide Objekte gültige Kraft, muss ich dazu beide Massen einbeziehen. Nachher, um die Beschleunigung des einzelnen Körpers zu errechnen muss ich aus der "gemeinsamen" Kraft die andere Masse wieder rausdividieren, denn in der Kraft stecken beide Massen und Beschleunigung ist
PHP:
a = F/m
(von F=m*a) Das hat mich dann zu dieser Variante geführt.
Deshalb ist auch meine "Accel" meiner Meinung auch genau das was sie bezeichnet nämlich die Beschleunigung und die wird bei mir in "DoStep" berechnet.
Der Funktion Move würde ich deshalb die Schrittweit als Parameter übergeben und den Code in der Funktion wie folgt anpassen:
freilich könnte man das machen aber genau wie vorher, muss man dann zweimal multiplizieren (mal 3 Komponenten) was ich mir durch den vorherigen Schritt erspart hab.

Man kann dann das Projekt als Ganzes kopieren und in der Methode Move die Midpoint-Methode implementieren.
Wie gesagt genau das wäre der nächste logische Schritt.
Diese Quelltextversion sollte nun genug optimiert sein um den Schritt zu gehen. Ausdrücklich ist jeder dazu eingeladen diese Version des Quelltext zu nehmen und Midpoint zu implementieren! :cool:

Eventuell sollte man die Methode Move auch umbenennen. Wie wäre es z.B. mit Planet::GetNextPosition(double schrittweite)?
einverstanden!

c) Bei der Klasse Planet fehlt mir noch der Destruktor, der den mit new reservierten Speicher für die Vektoren pos, Accel und Velocity wieder freigibt.
Gruß
Ja das ist richtig. War halt nicht so wild da die Planeten sowieso bis zum Ende vorhanden waren! Aber ist natürlich korrekt!

Andere Änderungen am Code:
- Planeten: Venus bis Saturn plus Erdmond
- Ausgabe geändert: Zeitschritte sind nun ca. ein Monat und nach 12 Schritten ( = 365 Tage) endet die Integration. Ausgabe nach jedem Monat. Ein Monat dauert bei mir nun 20sec.
- Klassen weiter aufgeräumt
- Genauigkeit: Fehler in X-Position nach 1 Jahr ca.102.000km (laut HORIZONS)
- Speedupdate aus letztem Beitrag von mir

Known Bugs:
- zu hohe Ungenauigkeit
- PSystem Destruktor fehlt (alle Planeten löschen) - unkritisch

Ab jetzt kommt in jedes Paket nurnoch die Quellcodedateien plus die geschwindigkeitsoptimierte EXE Datei.

RELEASE 02

fr0he 0stern
 
Zuletzt bearbeitet:

Bernhard

Registriertes Mitglied
Das ist in dem Fall nicht korrekt da es sich um Zeiger handelt und auch wenn die Zeigervariable selbst gelöscht wird so bleibt der Inhalt des Speichers erhalten, weshalb ein delete erforderlich ist.
Hallo Stefan,

das delete sollte trotzdem raus aus der Schleife. Das frisst wirklich unnötig Rechenzeit. Man alloziert besser einmal außen den Speicher (am besten ein einziges Mal beim Programmstart) und beschreibt die vorhandenen Speicherbereiche immer wieder neu mit den temporären Werten. Beim Programmende wird der Speicher dann wieder freigegeben. Bei den paar double-Werten sollte man das gut hinbekommen.

Aus Gründen der "mathematischen Correctness" wäre das richtig, aber da bei dieser Variante die Gconst mit multipliziert werden muss, hab ich sie gleich beim Festlegen der Masse einbezogen. So spart man sich die eine Multiplikation dort wo es auf speed ankommt.
OK. Sehr gute Idee.

Ausdrücklich ist jeder dazu eingeladen diese Version des Quelltext zu nehmen und Midpoint zu implementieren! :cool:
Der Unterschied zwischen beiden Verfahren ist nicht sehr groß:

Euler:
x_{n+1} = x_n + h * v_n(x_n)
v_{n+1} = v_n + h * a(x_n)

Das ist momentan auch so implementiert. Die Addition wird dabei über die Methode PVektor::Add umgesetzt.

Bei der Mittelpunkts-Methode verwendet man dagegen:
x_{n+1} = x_n + h * v_n(x_n + h/2 * v_n(x_n))
v_{n+1} = v_n + h * a(x_n + h/2 * a(x_n))

Hast Du als Test mal nachgesehen in wieviel Tagen der Mond um die Erde kreist?
Gruß und frohe Ostern
 
Zuletzt bearbeitet:

Bernhard

Registriertes Mitglied
Man alloziert besser einmal außen den Speicher (am besten ein einziges Mal beim Programmstart) und beschreibt die vorhandenen Speicherbereiche immer wieder neu mit den temporären Werten.
Ich sehe gerade, dass man dazu leider auch die Funktion PVektor::Sub umschreiben müsste, aber es lohnt sich. Du könntest z.B. die Adresse des Speichers für das Ergebnis als zusätzlichen Parameter übergeben und sparst dann pro Schleifendurchlauf das new und dann auch das delete.
 

Bernhard

Registriertes Mitglied
Bei der Mittelpunkts-Methode verwendet man dagegen:
x_{n+1} = x_n + h * v_n(x_n + h/2 * v_n(x_n))
Hi Stefan,

mir fällt gerade noch ein, dass der Term v_n(x_n + h/2 * v_n(x_n)) dummerweise nicht direkt berechenbar ist. Der Algorithmus zur Mittelpunkts-Methode passt also wegen der zweiten Ableitung noch nicht vollständig.

Bitte also, gemäß meiner Anleitung, noch nicht implementieren.

Die Theorie muss erst passen, sonst ärgert man sich bloß, weil der Code nutzlos ist - Sch...
Gruß
 
Zuletzt bearbeitet:

Bernhard

Registriertes Mitglied
Bei der Mittelpunkts-Methode verwendet man dagegen:
x_{n+1} = x_n + h * v_n(x_n + h/2 * v_n(x_n))
v_{n+1} = v_n + h * a(x_n + h/2 * a(x_n))
Ich habe da die Variablen x und v durcheinander gebracht. Richtig muss es heißen:

x_{n+1} = x_n + h * v_n + 0,5 * h^2 * a(x_n)
v_{n+1} = v_n + h * a(x_n + h/2 * v_n)

Die Beschleunigung muss bei diesem Verfahren pro Schritt, statt einmal, also zweimal berechnet werden und zwar an der Stelle x_n für den neuen Ort und an der Stelle x_n + h/2 * v_n für die neue Geschwindigkeit.

Wie man das herleitet kann man z.B. in den numerical recipes in C, Second edition, Kapitel 16.1 Runge-Kutta Method nachlesen.
 

SRMeister

Registriertes Mitglied
Nur nochmal zum Verständniss,

x_n - Aktueller Ort
v_n - aktuelle Geschw.
a - Beschleunigung?
h - Schrittweite
n aktueller Zeitpunkt
n+1 nächster (zu berechnender) Zeitpunkt


die Beschl. muss also hier quasi zweimal nur als Zwischenprodukt berechnet werden.
deshalb muss ich wohl erstmal die berechnung derselben auch in Planet::SetNewPos() verlegen, wie du ja schonmal vorgeschlagen hast.
Ist der Teil hier
a(x_n + h/2 * v_n)
als mathematischer Term gemeint, oder ist damit die Beschleunigung a an der Stelle (x_n + h/2 * v_n) gemeint? Eher das Zweite sonst ergibts für mich wieder keinen Sinn.
Ansonsten aber schon.
Ich berechne a also mehrmals: einmal am Anfang also bei x_n und bei a(x_n + h/2 * v_n).

Euler:
x_{n+1} = x_n + h * v_n(x_n)
v_{n+1} = v_n + h * a(x_n)

Das ist momentan auch so implementiert. Die Addition wird dabei über die Methode PVektor::Add umgesetzt.

Da ist mir gerade was aufgefallen. Ich glaube bei mir ist das so nicht implementiert, sondern folgendermaßen:
v_{n+1} = v_n + a(x_n)
x_{n+1} = x_n + v{n+1}

1. fehlt das h in den Gleichungen, was aber durch TconsSquare = h*h bereits weiter vorne eingerechnet ist (möglicherweise ist frühe quadrieren falsch)
2. benutze ich v(n+1) um x(n+1) zu berechnen was möglicherweise auch falsch ist.

Ich denke zuerst müssen wir die Fehler da ausräumen, die möglicherweise für die Abweichungen verantwortlich sind.
 
Zuletzt bearbeitet:
Oben