Wertebereich wie abfangen?



  • Hallo,
    das Programm gibt mir nach der Eingabe einer Zahl die Fakultät dieser Zahl aus.
    Jetzt möchte ich jedoch, das das Programm einen Fehler ausgiebt wenn die Fakultät höher ist als der Wert der in ein int passt.

    Laut aufgabenstellung soll ich das mit einem sizeof() lösen können. Nur nach langem grübeln komm ich einfach nicht drauf 😞

    Weis jemand wie ich das lösen kann?

    Gruss Michael

    /* *********************************** */
    /*   Constructed by ***   */
    /*        --*-- 05.2005  --*--         */
    /* *********************************** */
    
    #include <iostream.h>
    #include <conio.h>
    using namespace std; //C++ Zusatz
    
    void fKtFakultaet(int Zahl) 
    {
       /* Diese Funktion gibt die Fakultat von "Zahl" in einer Message aus" */
       /* Die Funktion muss folgendermaßen aufgerugen werden: fKtFakultaet(DeineZahl); */
    
       if(Zahl > 0)
       {
          /* Deklaration der Variablen */
          int rechZahl = 1;
    
          for(int i=1; i <= Zahl;i++)
          {
             rechZahl *= i;       
          }
    
          cout<<"Fakultaet von "<<Zahl<<" ist "<<rechZahl<<"!"<<endl;
       }
       else  //Fehlerausgabe
       {
           cout<<"Fehler: 'Zahl' darf nicht negativ sein!"<<endl;
       } 
    
    }
    
    int main() 
    {
    
       /* Deklarieren der Variablen */
       int eingZahl;              
    
       /* Testeingabe der Zahl */
       cout << "Eingabe der Zahl: ";
       cin>>eingZahl;   
    
       /* Aufruf der Funktion */
       fKtFakultaet(eingZahl);
    
       getch();
    
    }
    

  • Mod

    wie lautet denn die aufgabenstellung wörtlich?



  • sizeof() liefert Dir die Groesse der Variablen im Speicher zurueck (in Bytes). Um auf die maximalen Stellen eines unsigned Ints zu kommen muesste man demnach power(2, sizeof(int) * 😎 rechnen. Dies teilst du durch 2 (und musst davon glaub noch einen abziehen) und dann hast du den maximalen Wert im positiven Bereich.

    Aber genau betrachtet bringt dir das doch garnichts oder? Wenn du die Fakultaet berechnest kannst du ja in dem Sinn nicht prüfen, ob ein Überlauf stattgefunden hat, bzw ob die berechnete Zahl grösser als der Wertebereich ist, weil ja ein Überlauf stattgefunden hat. Du wirst wahrscheinlich am besten kommen, einfach zu testen, bis zu welcher Zahl man die Fakultaet berechnen kann und dann prüfen, ob die übergebene Zahl grösser ist (es sind ja ints, von daher sollte das gehen).

    Gruss,
    DeSoVoDaMu



  • Hallo

    DeSoVoDaMu schrieb:

    Du wirst wahrscheinlich am besten kommen, einfach zu testen, bis zu welcher Zahl man die Fakultaet berechnen kann und dann prüfen, ob die übergebene Zahl grösser ist (es sind ja ints, von daher sollte das gehen).

    Ich kann Dir da nicht ganz zustimmen, da es bei einer Fakultät das neue Ergebnis ein vielfaches des vorherigen ist. Das heißt Du hasst eventuell sogar mehrere Überläufe aber die zurückegebene Zahl ist trotzdem größer als die vorherige.

    Bsp:
    32 Bit
    Wertebereich: -2.147.483.648 bis 2.147.483.647

    Fakultät 12: 479.001.600 //kein Überlauf
    Fakultät 13: 6.227.020.800 //Überlauf

    6.227.020.800 - 2.147.483.647 - 2.147.483.648 = **1.932.053.504
    **
    Das Ergebnis ist deutlich größer als das Ergebnis von Fakultät 12. Jedoch ist es nicht das richtige Ergebnis von Fakultät 13.

    Ich hoffe das war verständlich und ich habe keinen Fehler gemacht.

    Gruß Alex



  • Ich meinte ja auch, dass er einfach prüft, ob die uebergebene Zahl groesser gleich 13 ist (weil, wie du wohl richtig sagst, dann der erste Überlauf stattfindet). Dann kann er entsprechend reagieren. Dies geschieht noch vor der eigentlichen Berechnung.

    Gruss,
    DeSoVoDaMu


  • Mod

    ich sehe auch keinen sinn darin, sizeof einzusetzen. eher benötigt man std::numeric_limits<int>::max() - den überlauf kann man abfangen indem man max() durch den aktuellen faktor teilt und nachsieht, ob das gegenwärtige produkt nicht bereits grösser ist. man kann das limit nat. auch hardcodieren wenn man faul ist 🙂



  • Entschuldigung DeSoVoDaMu,
    ich habe Deinen Post nochmal durchgelesen und habe ihn wohl beim ersten mal falsch verstanden. Habe wohl meinen ersten Gedanken reininterpretiert.

    Gruß Alex



  • Genaue Aufgabenstellung ist:

    Erstelle eine Funktion die den Wert der Fakultät einer Zahl berechnet und zurückgiebt.

    Als besonderheit soll der Algorithmus verhindern, dass zu grosse Fakultäten durch den Datentyp nicht gehalten werden können (z.B. 999).

    Tip: Mit sizeof(Datentyp) finden Sie heraus, wieviel Speicher ein Datentyp beansprucht.

    So stehts in der Aufgabenstellen.

    Ich hoffe mir kann da jemand weiterhelfen.

    Gruss Michael



  • Irgendwie ein blödes Beisiel Fakultät 999 ist eine Zahl mit 2565 Stellen.
    Naja vielleicht solls ja eine Aufgabe mit Aha Effekt sein.
    Der Vorschlag von Camper sollte dein Problem eigentlich schon lösen, das sizeof war ja nur ein Tip.

    Gruß Alex



  • ich gebe DeSoVoDaMu recht. natürlich macht man das am besten, indem man prüft, ob der parameter, von dem die fakultät berechet werden soll, nicht zu groß ist. der knackpunkt ist jedoch, daß dieser maximalwert eben von der bitbreite von int abhängt! du mußt also erst eine funktion schreiben, die diesen maximalwert in abhängigkeit von der bitbreite von int berechnet. anschließend kann dann deine fakultätsfunktion prüfen, ob das argument größer als dieser wert ist.

    ich würde vorschlagen, diese maximalwert-berechnungsfunktion so zu schreiben, daß erst der maximale positive wert von int berechnet wird (den man eigentlich auch aus <climits> bekommen kann :D) und diesen dann der reihe nach durch 2,3,4,5... dividiert, bis das ergebnis 0 wird. der vorhergehende divisor muß dann der maximalwert sein. wenn also nach division mit 24 eine 0 rauskommt, dann muß der maximale wert 23 sein.

    es könnten dabei vielleicht noch rundungsfehler auftreten. ich glaube das aber eher nicht.



  • Mhh,
    solche C++ befehle darf ich leider nicht verwenden :(.

    Ich sollte das ganze mit Verzweigungen (If) lösen.

    Ich probier noch etwas aus das ich nach jedem berechnen der Fakultät abchecke und vrgleiche. Vielleicht geht das ja.

    Wenn nicht werd ichs so machen wie ihrs mir geschildert habt.

    Gruss Michael



  • Noch eine kleine Frage, ich hab das mal in einem Tutorial gelesen weis jedoch nicht mehr wie das ging.

    Ich möchte in meinem Programm aus der Schleife rausspringen und an eine gewisse Stelle (Siehe Fett markiert) hinspringen. Bzw. ich möchte von A nach B springen egal ob das aus einer schleife heraus ist oder von irgendeinem anderen Teil des Programms ist.

    Ich weis nicht mehr genau wie das war, irgendwas mit "loop:" oder so.

    Ich hoffe mir kann da sjemand sagen.

    Könnt ihr mir bezüglich des einhaltens von der Integrität, Allgemeinheit, Effektivität, Klarheit und Einfachheit ein paar Tipps geben wie mans noch besser machen könnte?

    Gruss Michael

    [cpp]/* ************************************ */
    /* © Programmed by Michael /
    /* --*-- 29.05.2005 --
    -- */
    /* --'-- 15:00 --'-- */
    /* ************************************ */

    #include <iostream.h>
    using namespace std; //C++ Zusatz

    void fKtFakultaet(int Zahl)
    {
    /* Diese Funktion gibt die Fakultat von "Zahl" in einer Message aus" */
    /* Die Funktion muss folgendermaßen aufgerugen werden: fKtFakultaet(DeineZahl); */

    /* Kontrolle ob eingegebene Zahl größer 0 ist */
    if(Zahl > 0)
    {
    /* Deklaration der Variable /
    unsigned int rechZahl = 1; //Beginn bei 1 da sonst "0
    1"
    bool flag = 0;

    */* --> von break hier hin springen <-- /

    /* Auswertung / Berechnung der Fakultät */
    for(int i=1; i <= Zahl;i++)
    {
    rechZahl *= i;

    if(rechZahl == 0)
    {
    cout<<"Error: Ueberlauf des Datentyps 'unsigned int'! "<<endl;
    //long rechZahl=1;
    //Setze OK Flag auf Fehler!
    flag = 0;
    break; //nachher entfernen
    */* --> von hier nach oben springen <-- /
    }
    else
    {
    //Setze OK Flag!
    flag = 1;
    }
    }

    if(flag == 1)
    {
    /* cout<<"Fakultaet von "<<Zahl<<" ist "<<rechZahl<<"!"<<endl; */
    cout<<"Fakultaet: "<<rechZahl<<endl;
    }

    }
    else //Fehlerausgabe
    {
    cout<<"Fehler: Eingabe darf nicht '0' oder 'negativ' sein!"<<endl;
    }

    }

    int main()
    {

    /* Deklarieren der Variablen */
    int eingZahl;

    /* Testeingabe der Zahl */
    cout << "Eingabe der Zahl: ";
    cin>>eingZahl;

    /* Aufruf der Funktion. "eingZahl" ist die Eingabe Zahl */
    fKtFakultaet(eingZahl);

    /* Zeigt beim Ende des Programms "Drücken Sie eine beliebeige Taste ..." an */
    system("PAUSE");
    return 0;

    }[/cpp]



  • @de_MaStEr:
    Du könntest goto und ein Label benutzen, trotzdem ist dies in diesem Fall gänzlich abzuraten, da es den Code sehr unleserlich macht.

    Besser ist es wohl, wenn du die Funktion im Fehlerfall 0 zurückgeben lässt sprich:

    #include <iostream>
    using namespace std;
    
    unsigned int fak(int n)
    {
            unsigned int f = 1, f_before;
            for(unsigned int i = 2; i <= n; ++i)
            {
                    f_before = f;
                    f *= i;
                    if(f_before >= f)
                            return 0;
            }
            return f;
    }
    
    int main()
    {
            unsigned int r, n;
            do
            {
                    cout << "\n Please enter nr: ";
                    cin >> n;
                    r = fak(n);
                    if(r == 0)
                            cout << "\n Couldn't store such a great number\n";
            } while(r == 0);
            cout << "\n fakultaet of " << n << ": " << r << endl;
    
            return 0;
    }
    

    Oder was mit exceptions:

    #include <iostream>
    #include <stdexcept>
    using namespace std;
    
    unsigned int fak(int n)
    {
            unsigned int f = 1, f_before;
            for(unsigned int i = 2; i <= n; ++i)
            {
                    f_before = f;
                    f *= i;
                    if(f_before >= f)
                            throw overflow_error("Couldn't store such a great number");
            }
            return f;
    }
    
    int main()
    {
            unsigned int r = 0, n;
            do
            {
                    cout << "\n Please enter nr: ";
                    cin >> n;
                    try
                    {
                            r = fak(n);
                    }
                    catch(overflow_error& oe)
                    {
                            cout << oe.what() << '\n';
                    }
            } while(r == 0);
            cout << "\n fakultaet of " << n << ": " << r << endl;
    
            return 0;
    }
    

    /edit: Wobei die Prüfung auf Overflow sowohl bei dir als auch bei mir noch verbesserungswürdig ist. (Bin dazu aber jetzt zu faul... :))

    Caipi



  • Ich soll das ganze als eine Funktion bauen. Dieser funktion soll man nur den Wert geben und die Ausgabe soll später die Fakultät sein.

    Das mit dem vergleich geht leider bei mir nicht zuverlässig. Bricht aus unverständlichem grund schon viel zu früh ab obwohl der Datentyp noch einiges mehr aufnehmen kann.

    Denke das ist mit der loop sache schon ok aber leider weis ich nicht wie ich das anwenden muss. Kann mir das jemand kurz posten?

    Gruss MIchael



  • Hallo

    Caipi schrieb:

    /edit: Wobei die Prüfung auf Overflow sowohl bei dir als auch bei mir noch verbesserungswürdig ist. (Bin dazu aber jetzt zu faul... :))

    Das ist auf jedenfall verbesserungswürdig(siehe auch meinen vorherigen Beitrag), wobei ich hier die ganze Funktionsweise geändert habe.

    unsigned int fak(int n)
    {
            unsigned long long int f = 1;
            unsigned int result;
            for(int i = 2; i <= n; ++i)
            {
                    f *= i;
                    result=f;
                    if(f!=result)
                            return 0;
            }
            return result;
    }
    

    Es ist ja glaub nicht verboten intern eine long Variale zu benutzen.
    Du detektierst den Überlauf dadurch, das die errechnete Variable zu groß ist um sie dem int zuzuweisen.
    Gibt bei mir einen Überlauf bei i=13. Mein erster Versuch mit nur einem long hat nicht funktioniert, da unsigned long int und unsigned int bei mir den gleichen Datenbereich hatten.

    Gruß Alex



  • unsigned int fak(int n)
    {
            unsigned long long int f = 1;
            unsigned int result;
            for(int i = 2; i <= n; ++i)
            {
                    f *= i;
                    result=f;
                    if(f!=result)
                            return 0;
            }
            return result;
    }
    

    Funktioniert bei mir nicht. Wie funzt denn das mit dem Loop? Finde da leider nichts dazu 😞


  • Mod

    hier mal mit overflow prüfung ohne bezug auf bestimmte integer grössen:

    unsigned int fak(int n)
    {
        if ( n == 0 ) return 1;
        int result = n * fak( n - 1 );
        if ( result / n != fak( n - 1 ) ) return 0;
        return result;
    }
    


  • Hallo,

    ich verstehe gerade Deine Schwierigkeiten nicht. In der Schleife werden die Fakultäten berechnet.

    Alex_H schrieb:

    unsigned int fak(int n)
    {
            unsigned long long int f = 1;
            unsigned int result;
            for(int i = 2; i <= n; ++i)
            {
                    f *= i;         //berechne die Fakultät
                    result=f;       //weise das Ergebnis der Berechnung dem Integer Wert result zu
                    if(f!=result)//überprüfe ob Zuweisung erfolgreich
                            return 0;
            }
            return result;
    }
    

    Mit der if Bedingung überprüfst Du ob die Zuweisung erfolgreich ist, wenn ein Überlauf in der Integer Varibale entsteht unterscheidet sich daraufhin der Wert von dem Wert in der long Varibale. Nach einem Überlauf beendet die Funktion die Berechnung und gibt als Ergebnis 0 zurück.

    Eine genauer Beschreibung von funktioniert nicht wäre sehr hilfreich.
    Ansonsten erkläre bitte genauer was Du nicht verstehst.

    Gruß Alex



  • Hab das nun so wie du es hast eingebaut. Jedoch tut es leider nicht. Leider weis ich auch nicht warum 😞

    /* ************************************ */
    /*   © Programmed by Michael            */
    /*      --*-- 30.05.2005  --*--         */
    /*        --'--  17:00   --'--          */
    /* ************************************ */
    
    #include <iostream.h>
    using namespace std; //C++ Zusatz
    
    void fKtFakultaet(int Zahl) 
    {
       /* Diese Funktion gibt die Fakultat von "Zahl" in einer Message aus" */
       /* Die Funktion muss folgendermaßen aufgerugen werden: fKtFakultaet(DeineZahl); */
    
       /* Kontrolle ob eingegebene Zahl größer 0 ist */
       if(Zahl > 0)
       {
          /* Deklaration der Variable */
          unsigned long int rechZahl = 1;     //Beginn bei 1 da sonst "0*1"
          unsigned int CheckVar = 1;
          bool flag;
    
          /* Auswertung / Berechnung der Fakultät */
          for(int i=1; i <= Zahl;i++)
          {
             rechZahl *= i;  
             CheckVar = rechZahl;       
    
             if(rechZahl != CheckVar)
             //if(rechZahl == 0)
             {
                flag = 0; //setze Flag (Fehler)
                break; //nachher entfernen          
             }
             else
             {   
                 flag = 1; //setzt Flag (OK)
             } 
          }
    
          if(flag == 1)
          {
             cout<<"Fakultaet: "<<rechZahl<<endl; 
          }
          else
          {
             cout<<"Error: Ueberlauf des Datentyps 'unsigned int'! "<<endl;       
          }
    
       }
       else  //Fehlerausgabe
       {
           cout<<"Fehler: Eingabe darf nicht '0' oder 'negativ' sein!"<<endl;
       } 
    
    }
    


  • Hi,

    da es ja hier nicht um Performance geht und die ganzen 'long long'-Lösungen
    sicher nicht Aufgabenkonform sind, mal ein Tip von mir:

    Du musst doch einfach diese Ungleichung betracheten:

    n * fak(n-1) < maxint
    Also
    n < maxint/fak(n-1)
    

    Wennn du eine maxint-Konstante nicht nehmen darfst, dann kannst du diese
    mittels sizeof ja selber berechnen.

    Jockel


Anmelden zum Antworten