Wenn ich einen großen Fakultäts berechnen, warum bekomme ich eine negative Zahl?

StackOverflow https://stackoverflow.com/questions/236335

  •  04-07-2019
  •  | 
  •  

Frage

So, einfaches Verfahren, berechnet eine faktorielle Nummer. Code ist wie folgt.

int calcFactorial(int num)
{
    int total = 1;

    if (num == 0)
    {
        return 0;
    }

    for (num; num > 0; num--)
    {
        total *= num;
    }

    return total;
}

Nun, das funktioniert gut und Dandy (Es gibt sicherlich schneller und elegante Lösungen, aber das funktioniert für mich) für die meisten Zahlen. Jedoch bei der Eingabe größere Zahl wie 250 es, es klar zu sagen, Craps aus. Nun werden die ersten paar faktorielles "Bits" für 250 sind {250, 62250, 15126750, 15438000, 3813186000} Referenz.

Mein Code spuckt {250, 62250, 15126750, 15438000, -481.781.296 }, die offensichtlich ausgeschaltet ist. Mein erster Verdacht war vielleicht, dass ich die Grenze einer 32-Bit-Integer verletzt habe, aber wenn man bedenkt, dass 2 ^ 32 ist 4294967296 Ich glaube nicht. Das einzige, was ich denken kann, ist vielleicht, dass es eine unterzeichnet 32-Bit-Grenze durchbricht, aber es sollte nicht über solche Dinge denken können? Wenn Unterzeichnung das Problem ist, kann ich dieses Problem lösen, indem sie die ganzen Zahl ohne Vorzeichen, aber dies würde nur eine vorübergehende Lösung, da die nächsten Iteration Ausbeuten 938043756000, die weit über die 4294967296 Grenze sein.

So ist mein Problem der unterzeichnete Grenze? Wenn ja, was kann ich tun, große Zahlen zu berechnen (Obwohl ich eine „LargeInteger“ Klasse habe ich eine Weile her, dass gemacht geeignet sein kann!), Ohne wieder über dieses Problem zu kommen?

War es hilfreich?

Lösung

2 ^ 32 nicht, dass Sie für signierte ganze Zahlen, die Grenze nicht geben.

Die Signed Integer Grenze ist eigentlich 2147483647 (wenn Sie unter Windows sind die Entwicklung der MS-Tools, andere toolsuites / Plattformen würden ihre eigenen Grenzen haben, die wahrscheinlich ähnlich sind).

Sie werden eine große Anzahl Bibliothek C ++ benötigen wie diese .

Andere Tipps

Zusätzlich zu den anderen Kommentaren, ich möchte darauf hinweisen, zwei schwerwiegende Fehler im Code.

  • Sie haben keinen Schutz gegen negative Zahlen.
  • Die Fakultät von Null eins ist, nicht Null ist.

Ja, drücken Sie die Grenze. Ein int in C ++ ist, per Definition, signiert. Und, äh, nein, C ++ denkt nicht, nie. Wenn Sie es sagen, eine Sache zu tun, es wird es tun, auch wenn es offensichtlich falsch ist.

Betrachten wir eine große Anzahl Bibliothek. Es gibt viele von ihnen um für C ++.

Wenn Sie nicht angeben, signiert oder unsigniert, wird der Standard unterzeichnet. Sie können ändern diese eine Befehlszeilenoption auf Ihrem Compiler.

Denken Sie daran, C (oder C ++) ist eine sehr niedrige Ebene Sprache und tut genau , was Sie sagen, es zu tun . Wenn Sie es sagen, diesen Wert in einem signed int zu speichern, ist das, was es tun wird. Sie als Programmierer, um herauszufinden, wenn das ist ein Problem. Es ist nicht die Aufgabe der Sprache.

Mein Windows-Rechner ( Start-Ausführen-Calc ) sagt mir, dass

hex (3813186000) =         E34899D0
hex (-481781296) = FFFFFFFFE34899D0

Also ja, ist die Ursache der unterschriebene Grenze. Da factorials per Definition kann nur positiv sein, und kann nur für positive Zahlen berechnet werden, sowohl das Argument und der Rückgabewert sollte sowieso Zahlen ohne Vorzeichen sein. (Ich weiß, dass jeder int i = 0 in for-Schleifen verwendet, so tue I. Aber das beiseite gelassen, sollen wir immer unsigned Variablen verwenden, wenn der Wert nicht negativ sein kann, es ist gut, Praxis IMO).

Das allgemeine Problem mit factorials ist, dass sie leicht generieren sehr große Zahlen. Sie könnten einen Schwimmer verwenden, wodurch Präzision zu verlieren, aber das Integer-Überlauf Problem zu vermeiden.

Oh, Moment mal, nach dem, was ich oben geschrieben hätte, sollten Sie, dass ein nicht signierten Schwimmer machen; -)

Sie haben einen Überlauf Problem. Faktorielle kann leicht die Grenzen von ganzen Zahlen nicht überschreiten. Sie könnten Ihre Funktion ändern Doppelzimmer zurückzukehren, aber das wird man nur ein wenig mehr Raum kaufen. Bei Anwendungen, müssen Sie oft mehrfach factorials mal sehr geringe Stückzahl, wo das Endergebnis in einem Doppel passen, aber die Zwischenschritten nicht. Hier ist ein Artikel, der erklärt, wie mit dieser Situation umgehen:

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top