[gelöst] GSL und Random Number Generation
-
Das klingt so, als würdest du dauernd neue Klasseninstanzen erzeugen.
-
SeppJ schrieb:
Das klingt so, als würdest du dauernd neue Klasseninstanzen erzeugen.
Jap,
weil ich nach wie vor bei der Verschachtelung bin. Hab jetzt zwar das Linken gelöst aber dafür dieses Problem.Ich habe bisher drei Ebenen, wenn ich das so nennen darf.
Die main Datei, time_of_photon_income() und rng.hIn der main Datei wird nach der Zeit gefraft, d.h. mainWater.cpp ruft time_of_photon_income() auf.
Diese Funktion benötigt allerdings für ihre Ausübung eine Zufallszahl, sprich time_of_photon_income() ruft rng.h auf, genau gesagt dessen operator().Also jedes Mal, wenn ich eine Zufallszhal möchte, erzeuge ich alles, nur um es danach wieder zu vernichten.
Ich versuche das ganze ja als cpp Dateien separat zu kompilieren, um es dann im Programm nach belieben verwenden zu können.
Nur irgendwie ist das dann scheinbar der Nachteil?
Oder wie gesagt, ich muss ganz zu Beginn der mainWater.cpp Datei einmal RNG initialisieren und dann immer pointer darauf weitergeben.
Dann hätte ich etwas in der Art
#include "rng.h" #include "time_of_photon_income.h" using namespace std; int main(){// class RNG random; class RNG* p; cout << "Time: " << time_of_photon_income(p) << " fs" << endl; }
Und time_of_photon_income() muss dann entsprechend modifiziert werden.
double time_of_photon_income(class RNG* p){// }
Wobei ich hier wieder am Schwimmen bin, ob ich nicht in der Definition der Funktion noch den Adressoperator benötigen würde, also eher
double time_of_photon_income(class RNG* p &){//
Und wie würde ich dann den Operator () aufrufen?
Einfach sop->();
Wir müssen doch so nah dran sein!
Gruß,
Klaus.
-
Drei Methoden:
-Zufallsgenerator global machen
-Zufallsgenerator als Member einer Klasse
-Zufallsgenerator in einen Scope über den aufgerufenen Funktionen machen und immer herumreichenAlle Methoden repräsentieren jeweils ein unterschieldiches Konzept, wo der Zufallsgenerator lebt. Man kann nicht sagen, was besser oder schlechter ist, nur, ob es besser zu dem passt, was du möchtest oder nicht (Wobei Methode 3 ein bisschen wie Methode 2 für Arme ist).
Und ich bringe dir jetzt nicht die Syntax der Sprache, noch die Grundlagen von Klassen bei. Vielleicht findest du jemand anderen dafür, aber ich beschränke mich darauf, auf Lehrbücher zu verweisen.
-
Na gut,
einen letzten Anlauf unternehme ich noch.
Nachdem ich mit dem Syntax für den () Operator nicht zurechtgekommen bin, habe ich eine weitere Elementfunktion definiert get_random_number(), meine rng.h sieht jetzt so aus:
// rng.h #ifndef RNG_H #define RNG_H #include <time.h> #include <gsl/gsl_rng.h> class RNG{// public: RNG(); ~RNG(); gsl_rng* rng; double get_random_number(); double operator() (); }; RNG::RNG() { rng = gsl_rng_alloc(gsl_rng_default); gsl_rng_set (rng,time(NULL)); } RNG::~RNG() { gsl_rng_free(rng); } double RNG::operator() () { return gsl_rng_uniform(rng); } double RNG::get_random_number() { return gsl_rng_uniform(rng); } #endif
Das ganze klapp jetzt auch wunderbar in meiner mainWater.cpp Datei, wenn ich eine Instanz initialisiere, einmal mit . Operator oder mittels eines Pointers.
#include <iostream> #include "rng.h" using namespace std; int main(){// // class RNG random; // for(int i = 0; i < 10; i++) // { // cout << "Random Number: " << random.get_random_number() << endl; // } class RNG* pointer = new RNG; for(int i = 0; i < 10; i++) { cout << "Random Number: " << pointer->get_random_number() << endl; } return 0; }
:~/GSL/Cpp$ g++ -Wall -pedantic -ansi -c mainWater.cpp :~/GSL/Cpp$ g++ -L/usr/local/lib -o mainWater mainWater.o -lgsl -lgslcblas -lm :~/GSL/Cpp$ ./mainWater Random Number: 0.0408848 Random Number: 0.715352 Random Number: 0.0940853 Random Number: 0.0101064 Random Number: 0.226571 Random Number: 0.762686 Random Number: 0.363975 Random Number: 0.32461 Random Number: 0.994962 Random Number: 0.805768
Jetzt habe ich meine time_of_photon_income.h und .cpp soweit modifiziert, dass ein Pointer der Klasse RNG übergeben wird
// time_of_photon_income.h #ifndef TIME_OF_PHOTON_INCOME_H #define TIME_OF_PHOTON_INCOME_H double time_of_photon_income(class RNG* p); #endif
Und
#include <math.h> #include "rng.h" #include "time_of_photon_income.h" double time_of_photon_income(class RNG* p){// double mu = 12.5; double sigma = 5/sqrt(2*log(2)); bool condition = 0; double rand1 = p->get_random_number(); double rand2 = p->get_random_number(); double income_time = 0; while(condition == 0) { income_time = mu + sigma * sqrt(-2*log(rand1)) * cos(2*M_PI*rand2); if( 0 < income_time && income_time < 25) { condition = 1; } } return income_time; }
Was mich jetzt aber verwundert, dass ich Probleme mit dem Linker bekomme, weil Sachen mehrfach definiert wären. Dafür habe ich doch die header Dateien extra ge-guarded, oder nicht?
:~/GSL/Cpp$ g++ -Wall -pedantic -ansi -c time_of_photon_income.cpp :~/GSL/Cpp$ g++ -L/usr/local/lib -o mainWater mainWater.o time_of_photon_income.o -lgsl -lgslcblas -lm time_of_photon_income.o: In function `RNG::RNG()': time_of_photon_income.cpp:(.text+0x0): multiple definition of `RNG::RNG()' mainWater.o:mainWater.cpp:(.text+0x0): first defined here time_of_photon_income.o: In function `RNG::RNG()': time_of_photon_income.cpp:(.text+0x44): multiple definition of `RNG::RNG()' mainWater.o:mainWater.cpp:(.text+0x44): first defined here time_of_photon_income.o: In function `RNG::~RNG()': time_of_photon_income.cpp:(.text+0x88): multiple definition of `RNG::~RNG()' mainWater.o:mainWater.cpp:(.text+0x88): first defined here time_of_photon_income.o: In function `RNG::~RNG()': time_of_photon_income.cpp:(.text+0xa6): multiple definition of `RNG::~RNG()' mainWater.o:mainWater.cpp:(.text+0xa6): first defined here time_of_photon_income.o: In function `RNG::operator()()': time_of_photon_income.cpp:(.text+0xc4): multiple definition of `RNG::operator()()' mainWater.o:mainWater.cpp:(.text+0xc4): first defined here time_of_photon_income.o: In function `RNG::get_random_number()': time_of_photon_income.cpp:(.text+0xf4): multiple definition of `RNG::get_random_number()' mainWater.o:mainWater.cpp:(.text+0xf4): first defined here collect2: ld returned 1 exit status
Könntest du mir dabei bitte noch helfen, dann geh ich in mein stilles Kämmerchen lesen ...
Gruß,
Klaus.
-
Includeguards helfen nicht gegen mehrfache Definitionen. Die sind gegen mehrfache Deklaration. Daher: Keine Definitionen in Header oder wenn doch, dann inline.
-
SeppJ schrieb:
Includeguards helfen nicht gegen mehrfache Definitionen. Die sind gegen mehrfache Deklaration. Daher: Keine Definitionen in Header oder wenn doch, dann inline.
Okay,
meine rng.h sieht also wie folgt aus:// rng.h #ifndef RNG_H #define RNG_H #include <time.h> #include <gsl/gsl_rng.h> class RNG{// public: inline RNG(); inline ~RNG(); gsl_rng* rng; inline double get_random_number(); inline double operator() (); }; RNG::RNG() { rng = gsl_rng_alloc(gsl_rng_default); gsl_rng_set (rng,time(NULL)); } RNG::~RNG() { gsl_rng_free(rng); } double RNG::operator() () { return gsl_rng_uniform(rng); } double RNG::get_random_number() { return gsl_rng_uniform(rng); } #endif
Und jetzt funktioniert es auch in der mainWater.cpp mit der Übergabe des Pointers.
#include <iostream> #include "rng.h" #include "time_of_photon_income.h" using namespace std; int main(){// // class RNG random; // for(int i = 0; i < 10; i++) // { // cout << "Random Number: " << random.get_random_number() << endl; // } class RNG* pointer = new RNG; for(int i = 0; i < 10; i++) { cout << "Random Number: " << time_of_photon_income(pointer) << endl; } return 0; }
:~/GSL/Cpp$ ./mainWater Random Number: 10.0351 Random Number: 13.3335 Random Number: 10.5408 Random Number: 5.31796 Random Number: 18.6461 Random Number: 14.3153 Random Number: 14.1575
Das war es also?
SeppJ du bist der beste, tausend Dank, dass du trotz all meiner Fragen bei mir geblieben bist!!
Viele Grüße,
Klaus.
-
Da ist aber immer noch einiges falsch:
-Du musst unbedingt einen Kopierkonstruktor und Zuweisungsoperator definieren. Du hast gerade Glück, dass es auch ohne funktioniert. Google mal "Regel der großen Drei".
-Du hast immer noch Funktionsdefinitionen mit externer Bindung im Header. Das macht man, wie gesagt, nicht. Du hast nur zufällig den Header bloß ein einziges Mal benutzt, daher funktioniert es ausnahmsweise.
-Den mit new angeforderten Generator gibst du nie frei.Stilistische Fehler:
-Warum erstellst du überhaupt den Zufallsgenerator mittels new, wenn er doch in der main lebt? Dann kannst du doch dort auch einfach eine lokale Variable anlegen.*
-Das class vor RNG in Zeile 17 braucht man in C++ nicht, daher macht man es auch nicht.*: Da du den Generator dadurch nie kopierst, geht der fehlende Kopierkonstruktor durch. Die zwei Fehler heben sich hier quasi weg.
-
Mein lieber Herr Gesangsverein, jetzt machst du hier aber noch ein Fass auf!
Nicht falsch verstehen, ich bin ja froh darum.
Aber ich dachte ich hätte es jetzt 'geschafft', weil es klappt. Und jetzt kriege ich hier um die Ohren geschlagen, dass es eigentlich nur Zufall ist!
Langsam habe ich auch eine Ahnung davon was du unter Grundlagen verstehst. Nicht einfach den Syntax von C++ kennen, um einen Code runterschreiben zu können, sondern auch viel konzeptionelles dahinter im Zusammenhang mit Kompiler und Linker.
Wäre wahrscheinlich ähnlich wenn sich sich ein Physiker auf den Standpunkt stellt, dass er Physik machen möchte und keine Mathe.
SeppJ schrieb:
Du musst unbedingt einen Kopierkonstruktor und Zuweisungsoperator definieren. Du hast gerade Glück, dass es auch ohne funktioniert. Google mal "Regel der großen Drei".
Jau, habe danach gesucht und gleich den ersten Eintrag von Wikipedia genommen.
Jetzt verstehe ich auch besser die Zeile aus deiner Klasse:RNG(const RNG &); RNG& operator=(const RNG &);
Das ist der Kopierkonstruktor!
SeppJ schrieb:
Du hast immer noch Funktionsdefinitionen mit externer Bindung im Header.
Wie meinen? Es haben doch alle Funktionsdefinitionen der Klasse ein inline? Oder verwechsel ich das jetzt?
Man man man...
Gruß,
Klaus.
-
Klaus82 schrieb:
Wie meinen? Es haben doch alle Funktionsdefinitionen der Klasse ein inline? Oder verwechsel ich das jetzt?
Nein, ich hab das inline bloß nicht gesehen. Ich bin schon so gewohnt, dass man
class Foo { void bar() { /* Implementierung von foo::bar() */ } };
schreibt, wenn man inline meint, dass ich nach deiner Methode gar nicht richtig geguckt habe.
-
Okay,
also für meine Verhältnisse alles 'richtig'.
Dann bin ich wieder beruhigt.
Gruß,
Klaus.