C++ Übung



  • Hey Leute, hab hier eine Übung für C++ wo ich nicht weiterkomme, ich hoffe Ihr könnt mir da bisschen weiterhelfen. Es ist eine Übung aus der Uni (Ich besuche die Uni nicht, hole mir nur die Übungen). Ich habe nicht Probleme bei der Umsetzung, sondern ich weiß einfach nicht was von mir verlangt ist. Bei den Aufgaben 1 - 3 war alles gut beschrieben, was Verlangt war, bei dem hier ist kurz gehalten und ich weiß nicht genau was was ist.

    Die Aufgabe:

    Aufgabe 04

    Programmieren Sie zwei Funktionen, die das Minimum einer Funktion finden.

    Teil 1
    Die erste Funktion

    double findMinimum(double l, double r, double epsilon)

    soll eine Zahl x vom linken Rand l in Schritten von ε so lange in Richtung des rechten Randes r bewegen,
    bis sich der Wert der Funktion nicht mehr verringert. Der Funktionswert ist mittels

    evaluate(x);

    zu ermitteln. Dazu braucht man die Header Datei Function.h und Source Datei Function.cpp mit
    folgendem Inhalt:

    #ifndef FUNCTION_H_
    #define FUNCTION_H_

    void init(double a, double b, double c);

    double evaluate(double x);

    int getCount();

    #endif /* FUNCTION_H_ */

    #include "Function.h"

    namespace
    {
    double a_, b_, c_;
    int count = 0;
    }

    void init(double a, double b, double c)
    {
    a_ = a;
    b_ = b;
    c_ = c;
    }

    double evaluate(double x)
    {
    count++;
    return (a * x + b) * x + c;
    }

    int getCount()
    {
    return count;
    }

    Diese Dateien müssen man nicht abgegeben werden. Wichtig ist dabei, dass evaluate so selten wie
    möglich aufgerufen wird. Testen kann man die Funktion zum Beispiel mit:

    init(1.0, 2.0, 3.0);
    double x = findMinimum(-100.0, 100.0, 0.0001);
    std::cout << getCount () << " " << x << std::endl;

    Das sollte 990002 -0.99989999 ausgeben.



  • CPPler schrieb:

    soll eine Zahl x vom linken Rand l in Schritten von ε so lange in Richtung des rechten Randes r bewegen,
    bis sich der Wert der Funktion nicht mehr verringert. Der Funktionswert ist mittels

    evaluate(x);

    zu ermitteln.

    Was verstehst du daran nicht? Oder andersrum: was verstehst du daran?



  • Ja der Text ist eigentlich nicht nicht zu verstehen da er kurz und knapp gehalten ist aber in diesem Falle ist genau das mein Problem.

    Ich schreibe mein Gedankengang auf, dann kannst du mir sagen was stimmt und was nicht .

    Also "soll eine Zahl x vom linken Rand l in Schritten von ε so lange in Richtung des rechten Randes r bewegen,
    bis sich der Wert der Funktion nicht mehr verringert." ist relativ einfach erst dachte ich ein einfach Array würde es tun, aber den Gedanken habe ich schnell verworfen weil das mit epsilon nicht ausgehen würde, stattdessen würde ich sowas wie:

    while(l != r)
    {
    l += epsilon;
    }

    oder vielleich auch mit einer for-Schleife. Ich weiß nicht ob es bis hier richtig ist aber ab hier verstehe ich es auf jeden Fall nicht.

    evaluate verlangt ein Wert, was soll ich als Wert eingeben? Immer das was gerade durchgelaufen wird also in dem Fall einfach das ausgerechnete l? Wenn ja was ist dann damit gemeint das evaluate so wenige wie möglich aufgerufen werden soll?



  • Ja. Und dann vergleichst du den Returnwert von evaluate mit dem aus dem vorherigen Aufruf. Ist er nicht kleiner, bist du fertig.

    Deine Schleife könnte zu weit laufen: l kann größer als r werden, ohne jemals gleich gewesen zu sein.



  • Ich habe es mehrmals mit mehreren verschiedenen Schleifen versucht aber es kommt einfach nicht das richtige Ergebnis raus 😕 . Bei mit kommt 2000000 2 raus es sollte aber 990002 -0.99989999 rauskommen.

    double findMinimum(double l, double r, double epsilon)
    {
    double min = 99999999999999999.9, ev;

    for(l; l<=r; l+=epsilon)
    {
    ev = evaluate(l);

    if(ev < min)
    min = ev;
    }

    return min;
    }



  • Manni66 hat schon die Antwort auf einen Teil deiner Frage gepostet:

    manni66 schrieb:

    Deine Schleife könnte zu weit laufen: l kann größer als r werden, ohne jemals gleich gewesen zu sein.

    Wenn du diesen Kommentar beachtest, kommt schon einmal die richtige Anzahl Schritte heraus.

    Und zum Wert:
    Das Minimum der Funktion ist, wie man schnell sieht, der Punkt M(-1, 2). Da im Beispiel -1 herauskommen soll, ist in der Aufgabe wohl nach der X-Koordinate gefragt, du gibt aber die Y-Koordinate des Minimums zurück.

    Die Aufgabe ist offenbar nicht gut formuliert.



  • Ähm, ich wollte eigentlich "Ist er nicht kleiner, bist du fertig." von manni66 zitieren...



  • CPPler schrieb:

    double x = findMinimum(-100.0, 100.0, 0.0001);

    Das die x-Koordinate gesucht ist, hätte man auch am Beispiel-Code erahnen können. Trotzdem muss ich Euch recht geben, die Aufgabe ist nicht sauber formuliert.

    Der interessante Teil der Aufgabe ist eigentlich, dass evaluate() so selten wie möglich aufgerufen werden soll. Wenn man epsilon nicht als Konstante betrachtet könnte man ein Gradientenabstiegsverfahren implementieren und evt. schneller ans Ziel kommen (in Rechenzeit gesehen). Aber ich fürchte, dass geht zu weit und ist hier nicht gefragt.



  • ich stehe jetzt total aufm Schlauch XD. ich muss von links l nach recht r mit Schritten von epsilon das mache ich einfach mit l += epsilon, dann gebe ich jedes wert in evaluate ein das wäre dann l also evaluate(l); das was rauskommt vergleiche ich mit dem vorherigen also if(min > evaluate(l)) dann min = evaluate;

    die Umsetzung wäre dann bei mir

    double findMinimum(double l, double r, double epsilon)
    {
    double min = 99999999999999999.9, ev;

    for(l; l<=r; l+=epsilon)
    {
    ev = evaluate(l);

    if(ev < min)
    min = ev;
    }

    return min;
    }

    oder mit for Schleife

    double findMinimum(double l, double r, double epsilon)
    {
    double min = 99999999999999999.9, ev, pos = l;

    while(pos <= r)
    {
    ev = evaluate(pos);

    if(ev < min)
    min = ev;

    pos += epsilon;
    }

    return min;
    }

    das was zurückgegeben wird müsste normal die richtige Koordinate sein oder nicht? ich weiß nicht was ich sonst zurückgeben müsste 😕



  • "Ist [der Funktionswert] nicht kleiner, bist du fertig."
    Nicht: "Ist [der Funktionswert] nicht kleiner, laufe ich trotzdem bis r durch."

    Und was ist unklar an X vs Y?

    Und bitte benutze C++-Tags.

    Und bitte schalte Warnungen ein. Das hier:

    for(l; l<=r; l+=epsilon)
    

    sollte warnen... (auch wenn es so trotzdem richtig funktioniert).



  • Wie in den meisten fällen, gilt auch hier:

    y=f(x)y=f(x)

    Was ist dein f, was ist dein, x, was dein y und was wird als Rückgabe erwartet?



  • hmm ich hatte den Text total falsch verstanden, ich hatte den Text irgendwann gelesen und mich dann auf die Aufgabe irgendwann anders rangemacht XD. Ich Danke Euch für die nützlichen Tipps, ich werde mich am Wochenende die Aufgabe versuchen fertigzumachen (muss jetzt arbeiten^^). Nochmals vielen Dank an Alle! 👍



  • Hey Leute, Dank eure Hilfe habe ich das erste Teil gelöst und wollte mich heute an das zweite Teil ranmachen, aber schon wieder verstehe ich nicht was von mir verlangt ist. Die Aufgabenstellung:

    Die zweite Funktion

    double findMinimum2(double x1, double x4, double epsilon)

    implementiert eine Iteration mit Hilfe von vier Werten x1, x2, x3, x4, wobei
    x2 = x1 + (x4 − x1) ⋅ 0.38196601 und x3 = x1 + (x4 − x1) ⋅ 0.61803399 sein soll. Es sei nun y2 der
    Funktionswert an der Stelle x2, und y3 analog. Je nachdem, ob y2 < y3 ist, werden die vier Werte auf
    folgende Weise neu gesetzt:
    (Hier kommt ein Bild welches Ihr euch im Link ansehen könnt)
    https://einfprog.cosy.sbg.ac.at/content-angabeblaetter.html?show=4

    Dabei kommt jeweils ein neuer Wert hinzu, der nach obigen Formeln ermittelt wird. Das wird wiederholt,
    bis beide Abstände x3 − x2 und | y3 − y2 | kleiner als ε werden.

    Auch hier soll evaluate so selten wie möglich aufgerufen werden. Der Test

    init(1.0, 2.0, 3.0);
    double x = findMinimum2(-100.0, 100.0, 0.0001);
    std::cout << getCount() << " " << x << std::endl;

    sollte 30 -1.0000697 ergeben.

    mein Code sieht bisher so aus:

    double findMinimum2(double x1, double x4, double epsilon) 
    {
    	double l1 = x1, l2 = x1, y2, y3;
    	double x2 = x1 + (x4 - x1) * 0.38196601, x3 = x1 + (x4 - x1) * 0.61803399;
    
    	while(x3-x2 && fabs(y3 - y2) > epsilon)
    	{
    		for(l1; l1<=x2; l1 += epsilon)
    		{
    			evaluate(l1);
    		}
    		y2 = l1;
    
    		for(l2; l2<=x2; l2 += epsilon)
    		{
    			evaluate(l2);
    		}
    		y3 = l2;
    
    		if(y2 < y3)
    		{
    
    		}
    	}
    
    	return ;
    }
    

    wobei ich mir sicher bin dass es komplett falsch ist, ich hoffe auf Aufklärung, vielen Dank 🙂 !


  • Mod

    Es wäre ein Anfang, wenn du vielleicht auch was tust, mit den Ergebnissen deiner Rechnung.

    Ansonsten: Was genau ist deine Frage? Verstehst du die Aufgabe nicht?



  • 1. Überleg dir mal, was das hier bedeutet:

    while(x3-x2 && fabs(y3 - y2) > epsilon)
    

    Hinweis: eine double-Variable d ist genau dann wahr, wenn d==0 gilt.

    2. Wer hat dir dieses Pattern beigebracht?

    double d = start;
    // viel code
    // ...
    // noch mehr code
    for (d; d < irgendwas; d += irgendwas) ...
    

    Ich habe dir schon einmal geschrieben, dass du hier eine Warnung erhalten solltest - nämlich die, dass d eine ungenutzte Variable vor dem ersten Bereich der for-Schleife ist.

    Gewöhn dir an, die Schleifenvariable erst in der Schleife zu erstellen:

    for (double d = start; d < ende; d += irgendwas) ...
    

    Und mach nicht zu viel in einer Zeile. Dies hier ist total unübersichtlich:

    double l1 = x1, l2 = x1, y2, y3;
        double x2 = x1 + (x4 - x1) * 0.38196601, x3 = x1 + (x4 - x1) * 0.61803399;
    

    Besser:

    double x2 = x1 + (x4 - x1) * 0.38196601;
        double x3 = x1 + (x4 - x1) * 0.61803399;
    

    Die anderen Variablen brauchst du dort noch gar nicht. Vor allem erstelle nicht einfach irgendwelche Variablen, die du nicht initialisierst wie y2 und y2. Im while fragst du gleich als erstes, ob fabs(y3 - y2) > epsilon - aber da sind y2 und y3 noch nicht initialisiert!

    Du rufst zwar evaluate mehrmals in irgendwelchen Schleifen auf, aber du machst nichts mit dem Ergebnis... Denk mal drüber nach, ob du nicht doch wissen willst, was rauskommt...



  • Ich glaube der Trick ist, dass du den Abstand immer halbierst, bis er ε erreicht hat. Und weil die Funktion linear ist, kannst du in jedem Schritt die Richtung einfach umschalten, um dich dem Ziel zu nähern.

    Mein naiver Ansatz:

    abstand: s = length/epsilon 
       y1 = f(x), y2 = f(x+s)
    loop:
       s_halb = s/2
       wenn s_halb <= epsilon dann fertig!
       wenn y2 > y1 dann y3 = f(x+s-s_halb) 
           sonst wenn y2 < y1 dann y3 = f(x+s+s_halb)
       y1 = y2, y2 = y3, s = s_halb
       goto loop
    

  • Mod

    Andromeda schrieb:

    Ich glaube der Trick ist,

    Hier gibt es keine Tricks. Die Aufgabe nimmt einen doch Schritt für Schritt am Händchen und sagt genau, was wann zu tun ist. Man braucht nicht selbst zu denken, sondern muss einfach nur Deutsch nach C++ übersetzen. Malen Programmieren nach Zahlen!

    PS: Die Funktion ist nicht linear!



  • Zur Entspannung und Zerstreuung: 🙂
    https://en.wikipedia.org/wiki/Golden-section_search



  • SeppJ schrieb:

    PS: Die Funktion ist nicht linear!

    Stimmt, Sorry. 😞



  • Zuallererst die Funktion war nicht ganz fertig, ich habe sie trotzdem gepostet, weil ich nicht wusste was ich wo eingeben und wo ich was rausgeben soll und beim return wusste ich nicht mal nach welcher variable gefragt worden ist.

    @SeppJ, das Erste was ich nicht verstehe ist, "Es sei nun y2 der
    Funktionswert an der Stelle x2", soviel ich weiß sind doch die Funktionswerte das was eine Funktion zurückgibt, bei Teil 1 war es aber der Parameter, der gemeint war. Das zweite was genau ist gemeint y2 an der Stelle x2? Ist das damit gemeint das wenn ich bei evaluate an der Stelle ankomme welches x2 entspricht, dass dann y2 das ist was ich an dieser Stelle evaluate übergeben habe?
    Und von zu dem mit einfach von Deutsch nach C++ übersetzen: egal wie gut du Deutsch sprechen kannst wenn du etwas in eine andere sprache übersetzten musst, musst du auch dieses können und in C++ bin ich ein Neuling 😉

    @wob, 1. Das sollte eher so aussehen:

    while(x3-x2 > epsilon && fabs(y3 - y2) > epsilon)
    

    aber ja, ich denke das ist "weniger falsch" aber immer noch nicht richtig

    2. Das habe ich mir irgendwie selber angewöhnt, normalerweise wird immer double i; i<0, i++ etc. eingegeben aber es kommt vor dass man keine variable extra erzeugen muss sondern bestehende "verwerten kann", war in dem Fall nicht so, da wie du schon geschrieben hast, ich ungenutzte Variablen genutzt habe.

    3. Ich habe die Variable benutzt und dann initialisiert, das war sehr unbedacht.

    Ich glaub mittlerweile es hat kein Sinn die Übungen von der Uni zu machen da man ja normalerweise die Aufgaben nach Vorlesung gerichtet bekommt, da ich nicht weiß was die durchnehmen weiß ich auch nicht was mit den Zeichnungen gemeint ist.


Anmelden zum Antworten