Intervallschachtelung - Ergebnis ist immer 0



  • Hallo Leute,
    ich bin neu hier im Forum und habe ein Programm geschrieben, dass Wurzeln durch Intervallschachtelung berechnet, jedoch kommt als Ergebnis immer Null raus. Bevor ich hier den Quellcode "falsch" poste, würde ich gerne wissen wie man diesen hier ( im Forum, Nachrichtentext ) reinschreiben soll.
    Danke im voraus 🙂

    PS: Frohes Neues Jahr



  • Hi,

    du klickst unten bei den Smileys 2x auf "C++" und kopierst dann deinen Quellcode zwischen die beiden Tags rein.



  • Bevor du deinen Code postest gebe ich mal einen Tipp ab: Du machst irgendwo eine Integer-Divison, die 0 ergibt, z.B. 1/2 * x . Stattdessen direkt mit double-Literalen arbeiten: 1.0/2.0, etc.



  • Ok danke out,
    Dann hier hier Quellcode wenn ich alles richtig gemacht habe :

    #include <iostream>
    #include <cmath>
    #include <string> // Warum ich hier string eingebunden habe ist mir unbekannt
    using namespace std;
    
    int w = 1; // While - Schleifenvariable
    int f; // For - Schleifenvariable
    float ergebnis;
    float wurzel;
    int it;	// Iterationen
    float i_min; // Intervallminimum
    float i_max; // Intervallmaximum
    float i_mit; // Intervallmitte
    
    int up(float u )
    {
    	return u<0?u-.5:u+.5;
    }
    
    int down(float d )
    {
    	return d<0?d+.5:d-.5;
    }
    
    float intervall(float zahl, int i)
    {
    	i_max = up(sqrt(zahl));
    	i_min = down(sqrt(zahl));
    
    		for( f = 1; f >= i; f++ )
    		{
    			i_mit = ( i_min + i_max )/ 2 ;
    
    			if( pow(ergebnis, 2) >= zahl)
    			{
    				i_max = i_mit;
    			}
    
    			else if( pow(i_mit, 2) <= zahl )
    			{
    				i_min = i_mit;
    			}
    			else if( pow(i_mit, 2) == zahl ) continue;
    		}
    
    		return i_mit;
    }
    
    float check( float x)
    {
    	while( w != 0)
    	{
    		if( x <= 0 )
    		{
    			cout << "Bitte geben sie eine Zahl ueber 0 ein :";
    			cin >> x;
    		}
    		else
    		{
    			w = 0 ;
    		}
    	}
    
    	return x;
    }
    
    int main()
    {
    	cout << "Hallo" << endl;
    	cout << "Programm zu Berechnung einer Wurzel durch Intervallschachtelung" << endl;
    	cout << endl; 
    
    	cout << "Bitte geben sie eine Zahl ein: ";
    	cin >> wurzel ;
    	wurzel = check(wurzel);
    
    	cout << "Bitte geben sie an wie viele Iterationen durchgefuehrt werden sollen: ";
    	cin >> it ;
    	it = check(it);
    
    	ergebnis = intervall(wurzel, it);
    
    	cout << "Die Wurzel aus " << wurzel << " ist " << ergebnis << endl;
    
    	return 0;
    }
    

    Intervallschachtelung basiert ja darauf, dass man ungefähr wissen muss wo sich die Wurzel befindet,
    Beispiel Wurzel 2 :
    [1, 2]
    Da das Programm keine Inteligenz besitzt, ziehe ich direkt die Wurzel und runde dies dann auf und ab, mit einer Funktion die ich zufällig im Internet gefunden und verändert habe. Danach bestimmt die Schleife einen Nährwert.

    Bashar ich rechne mit Variablen ohne ihren Literal zu kennen, außerdem ist der Standertwert von float sowieso "0,00" 😉


  • Mod

    Bashar ich rechne mit Variablen ohne ihren Literal zu kennen

    Meinst du Typ? Das ist aber essentiell!

    , außerdem ist der Standertwert von float sowieso "0,00"

    Dir ist aber klar, dass lokale Variablen trotzdem mit 0 initialisiert werden müssen?

    int up(float u )
    {
        return u<0?u-.5:u+.5;
    }
    
    int down(float d )
    {
        return d<0?d+.5:d-.5;
    }
    

    Was sollen diese Funktionen überhaupt machen? Sieht ziemlich merkwürdig aus.

    Und am meisten fallen mir hier die globalen Variablen ins Auge. Ist ja der Wahnsinn! Warum deklarierst du f nicht einfach direkt im Schleifenkopf (Z. 30 statt 7)!?

    Mir ist auch nicht klar, warum die Funktion check nicht gleich die Variable einliest.



  • Zum ersten: Keine globalen Variablen.

    Denk nochmal über deine Variablentypen nach. Warum arbeitet check überhaupt mit float , wo du nur int haben willst?
    Genaugenommen willst du sogar unsigned int haben. Dann fällt auch die Überprüfung auf < 0 weg.

    Welchen Wert hat ergebnis in intervall und wie ändert der sich?

    Statt pow(zahl,2) nimmst du besser zahl*zahl

    Und nimm double statt float.

    Und noch etwas: Keine globalen Variablen.



  • Bashar ich rechne mit Variablen ohne ihren Literal zu kennen

    Ich hab es so interpretiert, dass Bashar meinte ich hätte den Literal der Variable beim deklarieren direkt initialisiert ( z.b int x = 5 ) und ich damit die Intervallschachtelung gemacht hätte.

    Dir ist aber klar, dass lokale Variablen trotzdem mit 0 initialisiert werden müssen?

    Nein das war mir nicht bewust, sorry

    int up(float u )
    {
        return u<0?u-.5:u+.5;
    }
    
    int down(float d )
    {
        return d<0?d+.5:d-.5;
    }
    

    Diesen Code habe ich hier zum Runden gefunden : http://www.c-plusplus.net/forum/39342-full

    Mir ist auch nicht klar, warum die Funktion check nicht gleich die Variable einliest.

    was meinst du damit ? 😕



  • Zeile 30.
    Und es ist schon ein schlechtes Zeichen, wenn du Variablendeklarationen mit einem Kommentar versehen musst, um zu wissen, wofür sie sind...
    C++ erlaubt es dir, Variablen überall zu deklarieren! Versuche sie erst zu deklarieren, wenn du ihr auch einen Wert geben kannst. Und vermeide globale Variablen!


  • Mod

    Diesen Code habe ich hier zum Runden gefunden :

    💡



  • Denk nochmal über deine Variablentypen nach. Warum arbeitet check überhaupt mit float , wo du nur int haben willst?

    Stimmt !

    Genaugenommen willst du sogar unsigned int haben. Dann fällt auch die Überprüfung auf < 0 weg.

    unsigned int ??

    Welchen Wert hat ergebnis in intervall und wie ändert der sich?

    als ich unter Zeile 32 noch

    cout << i_mit << endl;
    

    hinzugefügt habe kam trotzdem "Wurzel aus "wurzel" ist 0", also wurde die Schleife theoretisch einfach übersprungen

    Und danke für die tollen Tipps ( keine globalen Variablen) 😉



  • Und

    if( pow(ergebnis, 2) >= zahl)   // das bedeutet auch bei Gleichheit
                {
                    i_max = i_mit;
                }
    
                else if( pow(i_mit, 2) <= zahl )  // das bedeutet auch bei Gleichheit
                {
                    i_min = i_mit;
                }
                else if( pow(i_mit, 2) == zahl ) // Gleichheit, wie soll dieser Fall denn jemals eintreten, wenn du ihn vorher schon zweimal abgefangen hast?
                   continue;   // hier meinst du eigentlich break
    

    Fließkommazahlen auf Gleichheit zu testen geht meist in die Hose, da es immer Rundungs- und Darstellungsfehler gibt.



  • Zu dir Nathan :

    Und es ist schon ein schlechtes Zeichen, wenn du Variablendeklarationen mit einem Kommentar versehen musst, um zu wissen, wofür sie sind...

    Benutz du etwa keine Kommentare in deinem Quellcode ??
    Denkst du nicht auch dass es übersichtlicher ist die Variablen zu kommentieren ??

    C++ erlaubt es dir, Variablen überall zu deklarieren! Versuche sie erst zu deklarieren, wenn du ihr auch einen Wert geben kannst. Und vermeide globale Variablen!

    Die glabalen Variablen habe ich nur deklariert um alle an einem Punkt zu haben. Wenn das Programm fertig ist kann ich sie dann auch an einer anderen Stelle deklarieren 😉



  • continue;   // hier meinst du eigentlich break
    

    Dies stand so in meinem C++ Buch, break ist ja eigentlich eher für while-Schleifen, oder ?

    Fließkommazahlen auf Gleichheit zu testen geht meist in die Hose, da es immer Rundungs- und Darstellungsfehler gibt.

    Ich bin erst seit einigen Stunden im Forum registriert und schon lernt man viel neues dazu 😉



  • My_Ouzo schrieb:

    Genaugenommen willst du sogar unsigned int haben. Dann fällt auch die Überprüfung auf < 0 weg.

    unsigned int ??[/quote]
    unsigned int: Ganzzahl ohne Vorzeichen. Nur positive Werte.

    My_Ouzo schrieb:

    als ich unter Zeile 32 noch

    cout << i_mit << endl;
    

    hinzugefügt habe kam trotzdem "Wurzel aus "wurzel" ist 0", also wurde die Schleife theoretisch einfach übersprungen

    Nathan schrieb:

    Zeile 30.

    Deine Laufbedingung für die Schleife ist falsch. Die Bedingung (f>=i) muss wahr sein, damit die Schleif läuft
    Welche Werte hast du i? Ich denke mal mehr als 1.

    My_Ouzo schrieb:

    Benutz du etwa keine Kommentare in deinem Quellcode ??
    Denkst du nicht auch dass es übersichtlicher ist die Variablen zu kommentieren ??

    Gib deinen Variablen vernünftige Namen. Warum nennst du it nicht iterationen?

    My_Ouzo schrieb:

    Die glabalen Variablen habe ich nur deklariert um alle an einem Punkt zu haben. Wenn das Programm fertig ist kann ich sie dann auch an einer anderen Stelle deklarieren

    Nein, das schaffst du nicht.
    Wenn du die Variablen da definierst, wo sie gebraucht werden, dann brauchst du keine Kommentare.
    Dann sieht man, das es der for-Schleifenzähler ist.

    My_Ouzo schrieb:

    break ist ja eigentlich eher für while-Schleifen, oder ?

    Es gibt eigentlich keinen Unterschied zwischen for und while.



  • My_Ouzo schrieb:

    Und es ist schon ein schlechtes Zeichen, wenn du Variablendeklarationen mit einem Kommentar versehen musst, um zu wissen, wofür sie sind...

    Benutz du etwa keine Kommentare in deinem Quellcode ??
    Denkst du nicht auch dass es übersichtlicher ist die Variablen zu kommentieren ??

    Nein:

    for (int i = 0; ...
    

    Jeder weiß sofort, wofür i verwendet wird.

    size_t size = calc_size(...
    

    Jeder weiß sofort, was size speichert (ggf. noch zusätzlich const schreiben).

    bool is_smaller = a < b;
    

    Ebenfalls klar.

    Robert C. MartinClean Code schrieb:

    The proper use of comments is to compensate for our failure to express ourself in code.

    Nutze Kommentare für Dinge, die du nicht im Code ausdrücken kannst, bpsw.:

    ...
    i = size + 1; // wir müssen 1 addieren, da die später aufgerufene Funktion foobar32 ein anderes Intervall erwartet
    ...
    

    Schreib einfach bei komplexen Programmen bei der Funktionsdekleration hin, was die Funktion macht und was man beim Aufrufen beachten muss (ggf. noch Laufzeitkomplexität und Exceptionsafety).

    // macht eine sehr wichtige Aktion mit der übergebenen Variable value
    // index muss kleiner als size() und ptr, darf nicht null sein!
    // im Falle eines Fehlers wird value nicht verändert
    // der zurückgegebene Pointer bleibt für den Rest des Programmes gültig und muss nicht gelöscht werden
    T* some_func(int &value, std::size_t index, U *ptr);
    

    Man könnte ptr als Referenz übergeben um klar zu machen, dass null nicht erlaubt ist, aber das hab ich jetzt mal weggelassen. Beachte auch, dass ich durch das nutzen des vorzeichenlosen Typen size_t implizit verlange, dass index nicht negativ sein darf, weswegen kein Kommentar notwendig ist.



  • DirkB schrieb:

    Es gibt eigentlich keinen Unterschied zwischen for und while.

    for (Initialisierung; Test; Fortsetzung) 
      Anweisung
    

    gegenüber

    Initialisierung
    while (Test) {
      Anweisung
      Fortsetzung
    }
    

    Du kannst die beiden Schleifen gegeneinander austauschen.
    Es gibt noch einen Unterschied für den Scope (Sichtbarkeitsbereich) der Laufvariablen, wenn du sie bei der Initialisierung auch definierst.

    for nimmt man meist, wenn man die Anzahl der Durchläufe vorher weiß. while nimmt dann in den anderen Fällen.
    Das ist kein Zwang. Das kannst du machen wie du möchtest.



  • Von Poitern weiß ich leider noch nichts. Kommt erst in der Fortsetzung meines Buches dran. Außerdem besitze ich das Buch "C++ - Programmieren mit einfachen Beispielen" von Dirk Lous, und habe mich bereits bis "Klassen" / "Strukturen" durchgearbeitet. Als nächstes Kapitel kommt dann auch die objektorientierte Programmierung ins Spiel



  • So...
    ich habe jetzt meinen Quellcode überarbeitet, KEINE GLOBALEN VARIABLEN
    und noch die anderen Tipps beachtet:

    #include <iostream>
    #include <cmath>
    #include <string>
    using namespace std;
    
    int up(double u )
    {
    	return u<0?u-.5:u+.5;
    }
    
    int down(double d )
    {
    	return d<0?d+.5:d-.5;
    }
    
    double intervall(double zahl, int i)
    {
    	double i_min;
    	double i_max;
    	double i_mit;
    
    	i_max = up(sqrt(zahl));
    	i_min = down(sqrt(zahl));
    
    		int f;
    
    		for( f = 1; f <= i; f++ )
    		{
    			i_mit = ( i_min + i_max )/ 2 ;
    			cout << i_mit << endl;
    
    			if( pow(i_mit, 2) > zahl )
    			{
    				i_max = i_mit;
    			}
    
    			else if( pow(i_mit, 2) < zahl )
    			{
    				i_min = i_mit;
    			}
    			else if( pow(i_mit, 2) == zahl ) continue;
    		}
    
    		return i_mit;
    }
    
    int check( double x)
    {
    	int w = 1;
    
    	while( w != 0)
    	{
    		if( x <= 0 )
    		{
    			cout << "Bitte geben sie eine Zahl ueber 0 ein :";
    			cin >> x;
    		}
    		else
    		{
    			w = 0 ;
    		}
    	}
    
    	return x;
    }
    
    int main()
    {
    	double ergebnis;
    	double wurzel;
    	int iterationen;
    
    	cout << "Hallo" << endl;
    	cout << "Programm zu Berechnung einer Wurzel durch Intervallschachtelung" << endl;
    	cout << endl; 
    
    	cout << "Bitte geben sie eine Zahl ein: ";
    	cin >> wurzel ;
    	wurzel = check(wurzel);
    
    	cout << "Bitte geben sie an wie viele Iterationen durchgefuehrt werden sollen: ";
    	cin >> iterationen ;
    	iterationen = check(iterationen);
    
    	ergebnis = intervall(wurzel, iterationen);
    
    	cout << "Die Wurzel aus " << wurzel << " ist " << ergebnis << endl;
    
    	return 0;
    }
    

    Wenn ich als wurzel die Zahl 10 Einlese kommt bei 100 Iterationen 3 raus und bei der ersten 2,5 , d.h dass der Intervallanfang auf 2 gerundet wurde und das Ende eben auf 3.
    Außerdem bin ich mit ziemlich sicher, dass die Wurzel von 10 nicht 3 ist



  • Was erwartest du, wenn up und down int zurück geben?

    Mach dochkeinen großen Aufwand um die Startwerte

    i_max = zahl;
        i_min = 0;
    

    Mit break beendest du die Schleife.
    Mit continue läuft sie mit dem nächsten Durchlauf weiter. Nutzlos bei dir, da eh nichts mehr in der Schleife passiert.

    My_Ouzo schrieb:

    ...und noch die anderen Tipps beachtet

    Wieviel denn? Und wieviel nicht? Da stehst du nicht gut da.


Anmelden zum Antworten