Compilerfehler?



  • Hallo,

    ich habe ein kleines Programm in C++ geschrieben welches mir das Verhalten des Rundungsfehlers (oder besser ab welcher Schrittweite Rundungsfehler zu tragen kommen) "berechnet". Verwendet wird dazu das implizierte Euler Verfahren angewendet auf den harmonischen Oszillator. Normalerweise sollte ja ab einer gewissen Schrittweite der Fehler zur analytischen Lösung nicht mehr genauer werden, leider passiert das bei mir nicht. Ab einer gewissen Schrittweite wird einfach nur mehr der exakte Wert ausgegeben... Ist das ein Compilerfehler oder doch ein simpler Verständnis-/Programmierfehler?

    #include<cmath>
    #include<fstream>
    #include<iostream>
    #include<vector>
    #include<complex>
    
    using namespace std;
    
    float implicit_euler(float u0x, float u0v, float stepsize, int mode) {
    
    	float u1x, u1v;
    	float factor1, factor2;
    
    	factor1 = 1.0/(1.0+stepsize*stepsize);
    	factor2 = stepsize/(1.0+stepsize*stepsize);
    
    	u1v= factor1*u0v - factor2*u0x;
    	u1x = u0x + stepsize*u1v;
    
    	if (mode == 1) return u1x;
    	else return u1v;
    }
    
    float amp_phase(float ux, float uv, int mode) {
    
    	float amp, phase;
    
    	amp = (float)sqrt((float)pow((float)ux, (float)2.0)+(float)pow((float)uv, (float)2.0));
    	phase = (float)atan((float)uv/(float)ux);
    
    	if (mode == 1) return amp;
    	else return phase;
    }
    
    int main(void) {
    
    	// float max_variance = 0.00000001;
    	float stepsize = 0.9;
    	float sampling_x = 1.0;
    	float sampling_v = 0.0;
    
    	// int amp_i=0, pha_i=0;
    
    	float imp_x, imp_v, amp, phase, err_a, err_p;
    	float exct_x, exct_v, amp_ex, phase_ex;
    
    	ofstream file1 ("e_amp.txt");
    	ofstream file2 ("e_phase.txt");
    
    	for (int i = 0; i < 100; i++) {
    
    		imp_x = implicit_euler(sampling_x, sampling_v, stepsize, 1);
    		imp_v = implicit_euler(sampling_x, sampling_v, stepsize, 2);
    
    		exct_x = cos(stepsize);
    		exct_v = -sin(stepsize);
    
    		amp = amp_phase(imp_x, imp_v, 1);
    		phase = amp_phase(imp_x, imp_v, 2);
    
    		amp_ex = amp_phase(exct_x, exct_v, 1);
    		phase_ex = amp_phase(exct_x, exct_v, 2);
    
    		err_a = fabs(amp - amp_ex);
    		err_p = fabs(phase - phase_ex);
    
    		file1 << stepsize << " " << err_a << endl;
    		file2 << stepsize << " " << err_p << endl;
    
    		cout << amp << "    " << amp_ex << endl;
    		cout << phase << "    " << phase_ex << endl; 
    
    		stepsize = stepsize/2.0;			 
    	}
    
    	file1.close();
    	file2.close();
    
    	return 0;
    }
    

  • Mod

    Poolshark schrieb:

    Ist das ein Compilerfehler oder doch ein simpler Verständnis-/Programmierfehler?

    Richtschnur: Es bist immer du, nie der Compiler. Compiler werden täglich hunderte Millionen Mal benutzt. Fehler fallen daher entweder sehr schnell auf oder sind sehr sehr obskur - viel obskurer als alles was du in deinem Programm machst.

    Ich habe jetzt aber nicht die Muße, 100 Zeilen unkommentierten, relativ chaotisch aussehenden Code durchzugucken.



  • Richtschnur: Es bist immer du, nie der Compiler.

    Ich dachte mir ja das es nicht am Compiler liegen kann, aber dennoch kann ich es mir nicht erklären, warum das selbe Programm in C "richtige" Ergebnisse liefert und in C++ nicht.
    Um Licht in den undurchsichtigen Code zu bringen erkläre ich kurz worum es mir eigentlich geht:
    Ich verwende das implizierte Euler Verfahren (

    float implicit_euler()
    

    ) angewendet auf den harmonischen Oszillator. Wie in der Funktion zu sehen ist wird durch das Quadrat der Schrittweite dividiert (

    factor1, factor2
    

    ). Da die Schrittweite im Hauptprogramm nun immer kleiner wird ist zu erwarten, dass irgendwann Rundungsfehler (Maschinenfehler) auftreten. Da es sich um eine numerische Integration handelt sollte also bei

    float
    

    ab einer Schrittweite von 10-8 der Fehler von der numerischen zur analytischen Lösung nicht mehr kleiner werden. Das passiert bei diesem Code aber nicht...

    Ich habe bereits bemerkt, dass C++ bei Funktionen die double Werte verlangen float erzwungen werden muss (wenn man es braucht) -> Zeile 28/29

    Vielleicht kann mir jetzt jemand weiter helfen...

    Vielen Dank!



  • Poolshark schrieb:

    Da es sich um eine numerische Integration handelt sollte also bei

    float
    

    ab einer Schrittweite von 10-8 der Fehler von der numerischen zur analytischen Lösung nicht mehr kleiner werden.

    Wie kommst du gerade auf diese Zahl?

    Poolshark schrieb:

    Ich habe bereits bemerkt, dass C++ bei Funktionen die double Werte verlangen float erzwungen werden muss (wenn man es braucht) -> Zeile 28/29

    Äh wie? Was hast du genau "gemerkt"? Ich fürchte, du liegst damit falsch.



  • Hab mittlerweile das Problem gelöst. Es war einfach nur die Auflösung in der Schrittweite zu groß. Anscheinend wird, wenn eine Zahl eine gewisse Größe unterschreitet, einfach auf 0 gerundet (bei mir zumindest).

    Wie kommst du gerade auf diese Zahl?

    Diese Zahl kommt dadurch zustande da bei einer numerischen Integration eine Differenz von 2 immer kleiner werdenden Zahlen gebildet wird. Ab 10-8 reicht der reservierte Speicherplatz für einen double Wert also nicht mehr aus und es entstehen Rundungsfehler (Maschinenfehler). Wenn man also eine numerische Lösung mit einer Analytischen vergleicht wird der Fehler, ab einer Schrittweite von 10-8 also nicht mehr geringer sondern bleibt "annähernd" konstant.

    Vielen Dank für die Hilfe!
    Der Thread ist somit beendet.


Anmelden zum Antworten