Schleifendurchläufe zählen



  • Hallo zusammen! Ich bin noch sehr neu in C++ und habe dementsprechend noch paar Probleme. Ich bin gerade an einem Code dran, welcher die Wurzel einer Zahl berechnet was auch alles klappt. Nun sollte die Funktion auch den Typ int beinhalten welcher als Obergrenze für die Anzahl an Schleifendurchläufen genutzt werden soll.
    Das ist mein bisheriger Code jedoch wird als Schleifendurchlauf immer 100 ausgegeben. Irgendwie habe ich das Gefühl das ich irgendwas doppelt habe:

    #include <iostream>
    #include <iomanip>
    using namespace std;
    
    int main() {
    
      int i = 0;
      int n = 3;
      int zaehler = 1;
      double x = 1;
      double a;
    
      cout << "Geben Sie die Zahl unter der Wurzel ein: ";
      cin >> a;
      
      while ( i < 100 )
    {
      x = ( x + a / x ) / 2;
      i++;
      zaehler++;
    }
    
      cout << "Das Ergebnis ist: " << setprecision(n) << x << endl;
      cout << i << " Schleifendurchläufe";
      
      return 0;
    
    }
    

    Würde mich wirklich über Hilfe freuen 🙂



  • Schreibe bitte in eine Zeile vor Deinem Code ``` und in eine Zeile nach Deinem Code ```. Alternativ markiere Deinen Code und klicke auf das </> in der Symbolleiste über dem Eingabefeld.
    Du kannst Deine Beiträge auch im Nachhinein bearbeiten. Den Menüpunkt "Bearbeiten" findest Du in dem Drei-Punkte-Menü rechts unter Deinen Beiträgen.



  • @mondorano worin unterscheiden sich i und zaehler?



  • @mondorano "Nun sollte die Funktion auch den Typ int beinhalten welcher als Obergrenze für die Anzahl an Schleifendurchläufen genutzt werden soll". -> diesen Satz verstehe ich nicht. Kannst du das mal erläutern?

    i und zaehler unterscheiden sich nicht, außer das i bei 0 und zaehler bei 1 beginnt. Ebenfalls benutzt du zaehler nicht weiter.
    Der Zähler ist überflüssig.
    Bei Schleifen die einen Bezug auf Iterationen und eine definierte Grenze haben, nutze ich lieber eine for-Schleife. Find ich eleganter und besser lesbar als eine While- Schleife.

    for(int i = 0; i < 100; i++)
    {
    ....
    }
    

    Wenn du statt der 100 eine eingegebene Obergrenze haben willst, musst du diese einfach mit einer gesetzten Variable tauschen.

    int upper_bound = 100;
    for(int i = 0; i < upper_bound; i++)
    {
    ....
    }
    

    Für Wurzel Berechnung kannst du auch folgendes benutzen:
    std::sqrt()



  • @mondorano das immer die 100 für Schleifendurchlauf angegeben wird ist ja klar:
    du zählst in einer Schleife "i" 100x hoch und gibst am ende nach der Schleife das "i" aus. Wenn du die Schleife 50x laufen lässt, wird eine 50 ausgegeben usw.



  • @mondorano
    Du brauchst noch eine zweite Abbruchbedingung wenn du nicht willst dass die Schleife immer 100x durchläuft.
    Dazu könntest du dir z.B. den Wert vom vorigen Durchlauf in einer 2. Variable merken ( x_alt oder so), und dann x und x_alt vergleichen. Und wenn die beiden sich "ähnlich genug" sind, dann halt abbrechen.

    Wobei der einfachste Test für "ähnlich genug" natürlich Gleichheit ist. Dabei kann es dann aber auf Grund verschiedener Effekte sein dass die Schleife 100x durchläuft trotz dem das Ergebnis schon nach wenigen Durchläufen exakt war.

    Um das zu vermeiden kannst du eine "epsilon equals" Funktion wie die hier gezeigte nearly_equal verwenden:
    https://stackoverflow.com/a/32334103/454519



  • @hustbaer Ist das Newton's Methode?



  • @Swordfish Es wird als Heron-Verfahren bezeichnet: https://de.wikipedia.org/wiki/Heron-Verfahren
    Ist aber nix anderes als das Netwon-Verfahren für x² - a = 0.

    Also ja 🙂



  • @hustbaer thx



  • @Swordfish Auch lustig, falls du's noch nicht kennst: https://en.wikipedia.org/wiki/Fast_inverse_square_root



  • @hustbaer Kennt Doom nicht jeder? ^^
    Ich habe gefragt weil ich mir oft schwer tu von Code auf irgendwann einmal gelesenes zu schließen. Ist nicht immer alles im aktiven Arbeitsspeicher.
    Sollten die Werte für x nicht irgendwann anfangen zwischen zweien zu wechseln? Taugt das als Abbruchbedingung?



  • @Sicci Also am besten wäre glaube ich wenn ich dir die Aufgabe hier reinschicke dann ist das Verständnis auch besser denke ich.

    https://ibb.co/yX8Nj2v

    Habe das hier einfach mal hochgeladen. Hoffe ich darf das hier reinschicken.



  • @Swordfish sagte in Schleifendurchläufe zählen:

    Sollten die Werte für x nicht irgendwann anfangen zwischen zweien zu wechseln? Taugt das als Abbruchbedingung?

    Ich würde sagen: vermutlich ja, es sollte maximal ein Pendeln zwischen zwei Werten sein.

    Ich hatte das auch schon alles runtergetippt. Nur ist mir dann wieder eingefallen dass das mit Gleichheit bei Floating-Point halt so eine Sache ist.

    Wenn du diverse "fast math" Optimierungen an hast, und die passende Architektur + Compiler, dann kann es sein dass die Werte nie gleich testen obwohl sich schon lange nichts mehr ändert. Da hilft dann auf den vorletzten Wert prüfen auch nix mehr. Und zwar wenn der Compiler z.B. den aktuellen Wert von x noch in einem (breiteren) Register hat, den Wert von x_alt bzw. x_altalt aber aus dem Speicher liest. x87 hat z.B. 80 Bit breite FPU Register, da kann sowas passieren. Mit SSE sollte es mMn. nicht mehr vorkommen.
    Ebenso sollte es mit passenden Compiler-Einstellungen nicht passieren.



  • Wenn ich die Werte vor dem Vergleich explizit in einen double "zwinge" sollte das auf jeden Fall funktionieren.



  • @mondorano sagte in Schleifendurchläufe zählen:

    @Sicci Also am besten wäre glaube ich wenn ich dir die Aufgabe hier reinschicke dann ist das Verständnis auch besser denke ich.

    https://ibb.co/yX8Nj2v

    Habe das hier einfach mal hochgeladen. Hoffe ich darf das hier reinschicken.

    So wie die Aufgabe formuliert ist, reicht ein Test auf Gleichheit mit dem Wert aus dem letzten Durchlauf.



  • @Swordfish sagte in Schleifendurchläufe zählen:

    Wenn ich die Werte vor dem Vergleich explizit in einen double "zwinge" sollte das auf jeden Fall funktionieren.

    Jain.
    Laut MS-Doku nicht: https://docs.microsoft.com/en-us/cpp/build/reference/fp-specify-floating-point-behavior?view=msvc-160

    fast

    The /fp:fast option allows the compiler to reorder, combine, or simplify floating-point operations to optimize floating-point code for speed and space. The compiler may omit rounding at assignment statements, typecasts, or function calls.

    Wobei ich im Code nur einen Unterschied zwischen "fast" und "strict" sehen kann, "fast" und "precise" sind dagegen gleich: https://godbolt.org/z/6KxTae
    Laut Doku müsste es auch bei "precise" schon passen, also... pfuh. Keine Ahnung 🙂



  • @hustbaer sagte in Schleifendurchläufe zählen:

    Keine Ahnung

    I know that feeling.

    @hustbaer sagte in Schleifendurchläufe zählen:

    The compiler may omit rounding at assignment statements, typecasts, or function calls.

    Hm. Initialization steht da nicht 🙂



  • @Swordfish
    ps: GCC hat gleich gar keinen Modus indem mit x87 korrekt gerundet wird: https://godbolt.org/z/684EGr
    Siehe auch https://gcc.gnu.org/wiki/x87note

    ps2: Weil ich's grad noch ausprobiert habe: x = static_cast<MY_FLT>(x); reicht nicht 😉



  • Also ich habe die ganze Zeit versucht irgendwas hinzubekommen um mir die Schleifendurchläufe korrekt anzeigen zu lassen aber das lohnt sich noch nicht mal hier rein zu senden. Keine Ahnung wie ich das machen soll.



  • @mondorano
    Mit cout << Dings; kannst du den Inhalt/Wert von Dings ausgeben.

    Wie du es in deinem Programm schon selbst verwendet hast, kannst du auch mehrere << kombinieren, ala cout << i << " Schleifendurchläufe";
    Und wenn du endl ausgibst bekommst du einen Zeilenumbruch.

    Jetzt schreib in deine Schleife etwas rein mit dem du den aktuellen Durchlauf sowie den aktuellen Wert von x ausgibst.

    Sollte nicht so schwer sein.

    Ansonsten melde dich nochmal mit dem was sich deiner Meinung nach nicht lohnt hier zu zeigen. Wir werden dir gerne helfen wenn du wo was nicht verstehst, aber so direkt machen werden wir die Aufgabe nicht für dich. Also zumindest ich nicht.


Log in to reply