Wertebereich wie abfangen?



  • 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



  • Ich weiß zwar nicht was nicht funktioniert aber ich tippe mal auf die Erkennung des Überlaufs.
    Mir fällt auf das Du long int benutzt bei mir war das genau wie int eine 32 Bit Variable damit konnte es dann nicht funktioneieren.
    Abhilfe war dann long long int oder vielleicht auch __int64 gibts bei mir im BCB.

    Wenn das auch nicht klappt kannst Du ja die rekursive Lösung von Camper testen, die gefällt mir bis jetzt am besten. 👍

    Gruß Alex



  • Im Moment habe ich das Programm so wie unten.

    Wenn ich nun eine 23 eingabe geht das ganze in den Überlauf und es wird eine 0 ausgegeben obwohl eigentlich beide Variablen unterschiedlich sind. Normalerweise müsste er nun in die erste Bedingung springen oder?

    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;
          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;
       } 
    
    }
    


  • Ist zwar OT aber dennoch nicht ganz unwichtig:

    #include <iostream.h> 
    using namespace std;
    

    iostream**.h** ist veraltet. AFAIK gibt's in iostream.h auch gar kein std.

    Besser:

    #include <iostream> 
    using std::cout;
    using std::endl;
    


  • Habs nun mal ausgeben lassen:

    Eingabe der Zahl: 34
    rechZahl: 1 - CheckVar: 1
    rechZahl: 2 - CheckVar: 2
    rechZahl: 6 - CheckVar: 6
    rechZahl: 24 - CheckVar: 24
    rechZahl: 120 - CheckVar: 120
    rechZahl: 720 - CheckVar: 720
    rechZahl: 5040 - CheckVar: 5040
    rechZahl: 40320 - CheckVar: 40320
    rechZahl: 362880 - CheckVar: 362880
    rechZahl: 3628800 - CheckVar: 3628800
    rechZahl: 39916800 - CheckVar: 39916800
    rechZahl: 479001600 - CheckVar: 479001600
    rechZahl: 1932053504 - CheckVar: 1932053504
    rechZahl: 1278945280 - CheckVar: 1278945280
    rechZahl: 2004310016 - CheckVar: 2004310016
    rechZahl: 2004189184 - CheckVar: 2004189184
    rechZahl: 4006445056 - CheckVar: 4006445056
    rechZahl: 3396534272 - CheckVar: 3396534272
    rechZahl: 109641728 - CheckVar: 109641728
    rechZahl: 2192834560 - CheckVar: 2192834560
    rechZahl: 3099852800 - CheckVar: 3099852800
    rechZahl: 3772252160 - CheckVar: 3772252160
    rechZahl: 862453760 - CheckVar: 862453760
    rechZahl: 3519021056 - CheckVar: 3519021056
    rechZahl: 2076180480 - CheckVar: 2076180480
    rechZahl: 2441084928 - CheckVar: 2441084928
    rechZahl: 1484783616 - CheckVar: 1484783616
    rechZahl: 2919235584 - CheckVar: 2919235584
    rechZahl: 3053453312 - CheckVar: 3053453312
    rechZahl: 1409286144 - CheckVar: 1409286144
    rechZahl: 738197504 - CheckVar: 738197504
    rechZahl: 2147483648 - CheckVar: 2147483648
    rechZahl: 2147483648 - CheckVar: 2147483648
    rechZahl: 0 - CheckVar: 0
    Fakultaet: 0
    Drücken Sie eine beliebige Taste . . .

    Wirklich doof und solangsam versteh ichs nicht mehr 😞 Die Long variable müsste doch mehr fassen als die normale unsigned int?


  • Mod

    dE_MaStEr schrieb:

    Die Long variable müsste doch mehr fassen als die normale unsigned int?

    nope, nur mindestens genauso viel. nimm long long oder __int64 wenn du hast.



  • camper schrieb:

    dE_MaStEr schrieb:

    Die Long variable müsste doch mehr fassen als die normale unsigned int?

    nope, nur mindestens genauso viel. nimm long long oder __int64 wenn du hast.

    Danke nun sollte es gehn oder sieht noch jemand einen Fehler?

    Wenn nicht sag ich Danke an alle!

    Gruss Michael

    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 long int rechZahl = 1;     //Beginn bei 1 da sonst "0*1"
          unsigned int CheckVar;
          bool flag;
    
          /* Auswertung / Berechnung der Fakultät */
          for(int i=1; i <= Zahl;i++)
          {
             rechZahl *= i;  
             CheckVar = rechZahl;
    
             cout<<"rechZahl: "<<rechZahl<<" - CheckVar: "<<CheckVar<<endl;       
    
             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 'int'! "<<endl;       
          }
    
       }
       else  //Fehlerausgabe
       {
           cout<<"Fehler: Eingabe darf nicht '0' oder 'negativ' sein!"<<endl;
       } 
    
    }
    

Anmelden zum Antworten