Brauche Hilfe für folgende Übung



  • Hallo allerseits!

    Ich habe ein Problem mit folgender Aufgabe:

    Betrachtet folgende Bildungsvorschrift einer Zahlenfolge:
    x k+1 😞 3xk + 1 falls xk ungerade und xk=2 falls xk gerade).
    wobei x0 >= 0
    Unabhängig vom Startwert x0 nimmt die Folge nach endlich vielen Schritten periodisch die Werte (4; 2; 1) an. Beispiel:
    x0 = 5; x1 = 16; x2 = 8; x3 = 4 ; x4 = 2; x5 = 1; x6 = 4; x7 = 2; x8 = 1;....

    Nun zur Aufgabe:

    Programmiere mit Hilfe der while- und der if-Anweisungen ein Programm das die Folgenglieder dieser Folge zu einem festen x0 >= 0 berechnet und am Bildschirm ausgibt.

    Gehe bei der Lösung der Aufgabe folgendermaßen vor:

    1. Als Erstes deklariere zwei integer-Variablen x und k. In der Variablen x soll der aktuelle Wert xk und in k der Index von xk (Anzahl bereits ausgeführter Schritte) gespeichert werden.
      Initialisiere die beiden Variablen mit sinnvollen Werten, z.B. x0 = 27, k = 0.

    2. Überlege aus obigen Angaben zum Konvergenzverhalten der Folge eine Abbruchbedingung für die while-Schleife, so dass die periodischen Werte nur ein Mal berechnet werden.

    3. Programmiere in der Schleife die Berechnung der Folgenkomponenten xk.

    Nun ist meine Frage, wie die Lösung lautet?
    Ich bin ein Frischling auf dem Gebiet des c++ und nutze MS Visual Express.

    Soweit bin ich gekommen:

    #include<iostream>
    using namespace std;

    int main()
    {
    int x=27;
    int k=0;

    if (x >= 0) // wenn x >= 0
    {

    }

    Ist dieser Anfang überhaupt richtig? Ich weis nicht, wie ich weiterverfahren soll.

    Es wäre wirklich sehr hilfreich, wenn jemand hier mehr weis und es vermag die Aufgabe zu lösen (mit Kommentaren wäre es natürlich super! Da ich ja auch etwas lernen möchte :-))

    Vielen Dank schonmal im voraus! 🙂


  • Mod

    Aleph1 schrieb:

    Ist dieser Anfang überhaupt richtig?

    Das ist richtig, was nicht schwer ist, weil da so gut wie nichts steht.

    Ich weis nicht, wie ich weiterverfahren soll.

    Jetzt machst du innerhalb des if Blocks eine while-Schleife. In der Schleife führst du die vorgegebene Berechnung durch. Als Abbruchbedingung für die while Schleife bietet sich ja der Moment an, indem die Folge periodisch wird. Also wenn x gleich 1 ist.

    Es wäre wirklich sehr hilfreich, wenn jemand hier mehr weis und es vermag die Aufgabe zu lösen (mit Kommentaren wäre es natürlich super! Da ich ja auch etwas lernen möchte :-))

    Siehe dazu den Thread "Du brauchst Hilfe?". Hier machen wir keine Hausaufgaben.



  • SeppJ schrieb:

    Als Abbruchbedingung für die while Schleife bietet sich ja der Moment an, indem die Folge periodisch wird. Also wenn x gleich 1 ist.

    Diese Abbruchbedinung reicht nicht ganz aus, denn sie erfasst z.B. den Fall x0 = 1 oder x0 = 2 nicht und du müsstes somit nach der while-Schleife noch etwas hinfummeln. 😉

    Dann kommt mir gerade in denn Sinn wie man prüft ob eine Zahl gerade, also durch 2 teilbar ist. Ging doch irgendwie mit modulo, oder wie, oder was?



  • Danke erstmal für den Tipp!

    Aber wie kriege ich eine while schleife da rein, sodass sie der Aufgabe entspricht?

    Ich habe das hier versucht:

    #include<iostream>
    using namespace std;

    int main()
    {
    int x=27;
    int k=0;

    if (x >= 0)
    {
    while (x >= 0; x=1; x*3+1)
    {
    //Befehl????
    }

    }

    Aber irgendwie ist es falsch.



  • Reicht Deine Eigeninitiative nichtmal um nachzulesen wie eine while-Schleife funktioniert? Dazu gibt es nun wirklich MASSENHAFT Beispiele und tutorials nur einen Mausclick away von google... Kleiner Tipp: Das was Du da versuchst ist eine for-schleife...



  • und noch nen toller tipp:
    es gibt hier C/C++ Tags(unter den smilies, das ding ganz links^^)

    [ cpp]
    int main() {}
    [/cpp]
    ohne leerzeichen:

    int main()
    {}
    

    bb



  • Ups, danke für den Tip!

    #include<iostream>
    using namespace std;
    
    int main()
    {
    int x=27;
    int k=0;
    
    if (x >= 0) 
    { 
    	i = 1;
        while (x >= 0) 
        {
            cout << x << endl;
            x*3+1; 
        }
    
    }
    

    so besser?



  • von der formatierung her ists schon sehr viel besser
    vom quelltext her leider nicht

    ist noch immer fast 0 und das noch nicht korrekt
    was soll die zeile: i = 1; ?

    while (x >= 0) 
        {
            cout << x << endl;
            x*3+1; 
        }
    

    was willst du hier machen?
    eine endlosschleife bauen, weil x nie ein anderer wert zugewiesen wird?

    bb



  • #include<iostream>
    using namespace std;
    
    int main()
    {
    int x=27;
    int k=0;
    
    if (x >= 0) 
    { 
    
        while (x >= 0) 
        {
            cout << x << endl;
            x*3+1; 
        }
    
    }
    

    Wie weise ich denn x etwas zu? Sodass es mir die Ergebnisse wie in der Aufgabenstellungt anzeigt?

    Ich dachte nämlich:

    x muss grösser als null sein, wenn dem ist dann soll x*3+1 angezeigt werden (so habe ich die Aufgabe zumindest verstanden) 😕



  • x=x*3+1;
    😞



  • ohmann schrieb:

    x=x*3+1;
    😞

    dir scheint es echt an den grundlagen zu fehlen...
    ich hab mir die aufgabe zwar nicht durchgelesen, aber du solltest bevor du sie löst, noch mal dein buch/deine mitschriften/... durchlesen - dann wirst du hoffentlich nen ansatz zu stande bringen, der mehr als 5 zeilen umfasst...

    dann wird dir auch jmd richtig helfen...

    bb



  • Aleph1 schrieb:

    x muss grösser als null sein, wenn dem ist dann soll x*3+1 angezeigt werden (so habe ich die Aufgabe zumindest verstanden) 😕

    Ich fürchte du hast die Aufgabe falsch verstanden.

    Für den Startwert der Zahlenfolge gilt er muss größer oder gleich 0 sein.

    Also: X0 >= 0

    Die Bildungsvorschrift für die restliche Zahlenfolge (X1, X2, X3, ...) lautet (vermutlich!):

    3 * X[t]k[/t] + 1 , falls X[t]k[/t] ungerade
    X[t]k+1[/t] = 
            X[t]k[/t]/2, falls X[t]k[/t] gerade
    

    Vermutlich deshalb, weil du oben

    x k+1 😞 3xk + 1 falls xk ungerade und xk*=*2 falls xk gerade).

    stehen hast. In meinen Augen macht das "=" da keinen Sinn. Wenn man allerdings stattdessen Xk/2 annimmt, dann stimmt die Aussage mit der Unabhängigkeit vom Startwert nicht mehr, da für X0 = 0 eine Nullfolge entsteht, ohne dass die Werte 4, 2, 1 auftauchen würden.

    Hast du dich da vertippt, oder steht die Zeile
    x k+1 😞 3xk + 1 falls xk ungerade und xk=2 falls xk gerade)
    wirklich genau so in der Aufgabenstellung?



  • Hallo Mitleid!

    Ja das steht da wirklich so.
    Also bin ich jetzt soweit:

    #include<iostream>
    using namespace std;
    
    int main()
    {
    int x=27;
    int k=0;
    
    if (x >= 0) 
    { 
        while (x >= 0) 
        {
            cout << x << endl;
            x=3*x+1; 
    
    		if (3%2==1)
    		{
     }
        }
    
    }
    

    Aber irgendwie scheint es noch immer nich richtig zu sein, kann mir einer bitte weiterhelfen?



  • Aleph1 schrieb:

    Ja das steht da wirklich so.

    Hm, dann würde ich mich nochmal erkundigen, was damit gemeint sein soll, denn das macht irgendwie keinen Sinn.

    Aleph1 schrieb:

    Aber irgendwie scheint es noch immer nich richtig zu sein, kann mir einer bitte weiterhelfen?

    Es können und wollen dir sicher ein paar Leute helfen. Werner Salomon juckt es wahrscheinlich schon in den Fingern. 😃 😃

    Aber, was du bisher gezeigt hast legt die Vermutung nahe, dass du dich weder mit C++ noch mit der Aufgabenstellung richtig befasst hast. Und es wäre fahrlässig dich dieser Denk- und Fleißaufgaben zu berauben, denn nur so kommt ein Lernprozess in Gang.

    Sieh dir die Sachen genauer an, mach dir klar was verlangt wird und stelle dann konkrete Fragen. 😉 Die Aufgabenstellung ist recht simpel.



  • Soweit bin ich nun liebe community!

    #include<iostream>
    using namespace std;
    
    int main()
    {
    int x=27;
    int k=0;
    
    if (x >= 0)
    {
    while(k<9)
    {
    cout << x << endl;
    x=3*x+1;
    
    if(k%2 != 0)
    {
    x=3*x+1;
    }
    }
    
    }
    

    Ich hab mir nun wirklich Mühe gegeben...ist es bis hierhin richtig?
    Wie sollte ich nun die Else-Abfrage konstruieren? Kann mir hier bitte einer helfen?



  • gucken wir erst noch mal die aufgabe durch und schauen, was dort so drin steht:

    Betrachtet folgende Bildungsvorschrift einer Zahlenfolge:
    x k+1 😞 3xk + 1 falls xk ungerade und xk=2 falls xk gerade).
    wobei x0 >= 0
    Unabhängig vom Startwert x0 nimmt die Folge nach endlich vielen Schritten periodisch die Werte (4; 2; 1) an. Beispiel:
    x0 = 5; x1 = 16; x2 = 8; x3 = 4 ; x4 = 2; x5 = 1; x6 = 4; x7 = 2; x8 = 1;....

    ok, erst mal fertig durchlesen...

    Programmiere mit Hilfe der while- und der if-Anweisungen ein Programm das die Folgenglieder dieser Folge zu einem festen x0 >= 0 berechnet und am Bildschirm ausgibt.

    -> wir haben offensichtlich ein x0 >= 0 gegeben. und sollen dann was damit machen

    1. Als Erstes deklariere zwei integer-Variablen x und k. In der Variablen x soll der aktuelle Wert xk und in k der Index von xk (Anzahl bereits ausgeführter Schritte) gespeichert werden.
      Initialisiere die beiden Variablen mit sinnvollen Werten, z.B. x0 = 27, k = 0.

    int k = 0; anfang -> index = 0
    int x = gegebener_anfangs_wert; ist klar, x0 sollte ja iwie gegeben sein...

    1. Überlege aus obigen Angaben zum Konvergenzverhalten der Folge eine Abbruchbedingung für die while-Schleife, so dass die periodischen Werte nur ein Mal berechnet werden.

    klingt eigtl rel. einfach, nehmen wir einfach nen array mit ner länge von 3 und speichern dort die letzten 3 zahlen - gibt 2 möglichkeiten, wie wir das tun - entweder, indem wir uns den anfang merken oder indem wir immer hin und her kopieren... ich werds mal mit dem anfang merken versuchen...

    1. Programmiere in der Schleife die Berechnung der Folgenkomponenten xk.

    ist klar, dass wir das tun wollen^^

    also:

    const int x0 = 27; //unser gegebener startwert hier als globale konstante, damit man ihn schnell ändern kann
    //von einlesen steht nix in der aufgabe, also machen wir uns auch nicht mehr arbeit, als wir müssen
    
    //wir bauen uns erst mal ne fkt, die nen array und den anfang übergeben bekommt und für uns checkt, ob wir abbrechen drüfen
    bool convert(int *last_values, int index);
    
    int main()
    {
      int k = 0;
      int x = x0;
    
      int last_values[3] = {}; //0-initialisiert
    
      while(!convert(last_values, k))
      {
        if(k%2 == 0) //2 teilbar
        {
          x = 3*x +1;
          k = k+1;
        }
        else
        {
          x = x/2;
          k = k+1;
        }
        //unser merker für das konvergenz-verhalten muss noch aktualisiert werden:
        last_values[k%3] = x;
      }
    }
    
    bool convert(int *last_values, int index)
    {
      int first = index%3,
        second = (index+1)%3,
        third = (index+2)%3;
    
      return (last_values[first] == 1) && (last_values[second] == 2) && (last_values[third] == 4);
    }
    

    und schon wären wir fertig...
    (also für den fall, dass hier keine fehler mehr drin wären^^)

    ich würd es allerdings noch ein wenig anders schreiben...

    const int starting = 27;
    
    bool convert(int* last_values, int index)
    {
      bool R = values[index%3] == 1;
      R &= values[++index%3] == 2;
      R &= values[++index%3] == 4;
    
      return R;
    }
    
    int main()
    {
      int k = 0;
      int x = starting;
    
      int last_values[3] = {};
    
      while(!convert(last_values, k))
      {
        if(k%2 == 0)
        {
          x *= 3;
          ++x;
        }
        else
        {
          x /= 2;
        }
        ++k;
    
        last_values[k%3] = x;
      }
    }
    

    heißt nicht unbedingt, dass es so schöner ist, aber ich finds so übersichtlicher^^

    ich hab zwar nicht mit absicht fehler reingemacht, aber das hat nix zu sagen ;o)

    bb



  • @unskilled
    Das geht doch sicher noch schöner, oder?

    Z.B. ohne dieses Array und die zusätzliche Funktion. Du willst doch Aleph1 nicht unnötig verwirren, was?

    Übrigens würde der Startwert x0=0 bei dir zu einer Endlosschleife führen. Da ist aber auch die Aufgabenstellung recht schlampig formuliert.



  • Diese Folge ist die sogenannte Collatz-Folge und endet nach heutigen Kenntnisstand immer mit einer 1. Zudem ist sie ein schönes Beispiel für die Anwendung des boost.iterator_adaptors wie folgender Code zeigt:

    #include <algorithm> // copy
    #include <iterator> // ostream_iterator
    #include <iostream>
    #include <boost/iterator/iterator_adaptor.hpp>
    
    template< typename T >
    class basic_collatz : public boost::iterator_adaptor< basic_collatz< T >, T, T, boost::forward_traversal_tag, const T >
    {
    public:
        explicit basic_collatz( const T& x )
            : iterator_adaptor( x )
        {}
        void increment()
        {
            if( base_reference() % 2 == 0 )
                base_reference() /= 2;
            else
                ++( base_reference() *= 3 );
        }
        T dereference() const { return base_reference(); }
    };
    typedef basic_collatz< int > Collatz;
    
    int main()
    {
        using namespace std;
        for( int x; cout << "> ", cin >> x && x > 0; )
        {
            copy( Collatz( x ), Collatz( 1 ), ostream_iterator< int >( cout << "Collatz-Folge: ", " " ) );
            cout << endl;
        }
        return 0;
    }
    

    Gruß
    Werner

    PS.: nein - dieser Beitrag war nicht für Aleph1 gedacht 😉


  • Mod

    Es ist auch gar nicht nötig, sich drei Folgemitglieder zu merken. Da das aktuelle Glied nur vom Vorgänger abhängt, reicht es, auf 1 zu prüfen, denn wenn man erstmal bei der 1 ist, kommt danach immer 4,2,1.



  • SeppJ schrieb:

    Es ist auch gar nicht nötig, sich drei Folgemitglieder zu merken. Da das aktuelle Glied nur vom Vorgänger abhängt, reicht es, auf 1 zu prüfen, denn wenn man erstmal bei der 1 ist, kommt danach immer 4,2,1.

    hmmm... richtig xD
    ok, hätte man auch von selbst drauf kommen können ;o)
    ich überleg gerade, ob ich wohl die ausrede mit der uhrzeit bringen kann... aber ich denke, ich geb einfach zu, dass ichs verkackt hab 😉

    bb


Log in to reply