C++ Rechenvorgang mit Variablen liefert immer das selbe Ergebnis

TheShooter

Lt. Junior Grade
Registriert
Juni 2011
Beiträge
370
Hallo,
ich habe ein paar Funktionen programmiert, die mir das Leben etwas vereinfachen sollen. Nun möchte ich mit diesen rechnen, nur ich verstehe nicht, warum jedesmal das gleiche Ergebnis (-2147483648) rauskommt. Kann es sein, dass die Zahlen nicht in die Variablen passen?
Hier ein Codeausschnitt:

Code:
int faculty(int n)
{
    long long result = 1;
    for(int i = 1; i<=n; i++)
    {
        result *= i;
    }
    return result;
}

[...]

int calc(int people)
{
    long double probability = 1;

    probability = (faculty(365)/(faculty(365 - people) * pow(365,people))) * 100;
    return probability;
}

Die Funktion wird später folgendermaßen aufgerufen:

Code:
int input;
cin >> input;

[...]

cout << calc(input) << endl;

Wo liegt hier das Problem?

Wäre dankbar für Hilfe! ;)

Beste Grüße,
TheShooter
 
Auf den ersten blick passt der return schon mal nicht mit den Variablen zusammen. Wenn du double hast solltest du auch double zurück geben oder seh ich da grad irgendwas falsch?
 
Du hast recht, habe die Datatypes vereinheitlicht, nun kommt, egal welche Variable ich als Input liefere, immer das Ergebnis "0" raus.
Woran kann das liegen?
 
Code:
double pow (double base, double exponent);

Hab grad zwar nicht wirklich ne ahnung was die Funktion tun soll ;) aber es sollen beide Datentypen double sein. Bei dir ist people int.

Bei mir hat sowas früher aber glaube immer copiler fehler gegeben. Ist alles solange her
 
Meine 2 Cent:

Das Problem wird sein, dass deine Funktion faculty() int liefert.

Später rechnest du dann u.a. faculty(365) / (faculty(365 - people). Das wäre dann int durch int, was wieder int ergibt. Daraus folgt, dass alles kleiner 1 zu 0 und damit der Rest des Terms 0 wird.
 
Zuletzt bearbeitet:
Ich verstehe nicht warum du permanent versuchst int werte zurückzugeben obwohl in den Funktionen ganz andere Datentypen benutzt werden.

In der ersten benutzt du "long long result = 1;" und dann versuchst du einen Int Wert zu returnen, zwar sind beide Datentypen Ganzzahlig aber long long ist um einiges "breiter" aufgestellt.

in der zweiten Funktion benutzt du "long double probability = 1;" und versuchst dann einen Fließkommawert in einen Ganzzahltypen int zu returnen. Ich kenne mich bei c++ nicht sonderlich gut aus, ich kann mir aber kaum vorstellen dass das korrekt ist. Sowieso bin ich verwundert dass er dich das compilen lässt, bei java wäre definitiv nen Error gekommen.
 
Hast du dir schonmal überlegt wieviel 365! ist? Ziemlich viele Stellen, da ist auch ein long long int ein vollkommen nutzloser Zwerg dagegen.
 
Ja, mir ist schon klar, dass 365! eine verdammt große Zahl ist. :) Aber es muss doch eine Möglichkeit geben mit solchen Werten rechnen zu können? Mein Taschenrechner kanns doch auch?!
 
Wie firespot schon gesagt hat, ist selbst der Datentyp long long viel zu klein für die großen Zahlen. Ab Fakultät 20 kommt es da schon zum Überlauf im Zahlenbereich.
Starte das Programm einfach mal mit dem Debugger und schau dir an wie sich die Variablen da entwickeln.
 
Dein Taschenrechner wird aber wohl kaum mit 32-bit ints rechnen ...

Ein paar Ansätze:

-) eine Bibliothek mit arbitrary-precision-numbers verwenen (gibts einige)
-) an der Logik schrauben. Da du eine Fakultät durch eine andere dividierst kürzt sich da im Endergebnis ein Menge raus.
-) statt einer selbstgebastelter, etwas naiv implementierten (ist überhaupt nicht böse gemeint, nur matter auf fact im Sinne von numerical issues) Fakultätsfunktion die Gammafunktion verwenden.

mischt man von oben die Aspekte Bibliothek, Logik und Gammafunktion, dann kommt man dabei zur Funktion tgamma_ratio aus der Maths-library von boost:
http://www.boost.org/doc/libs/1_55_0/libs/math/doc/html/math_toolkit/sf_gamma/gamma_ratios.html

Anmerkung: Die Gammafunktion ist NICHT direkt die Fakultät - aber 'so nahe dran' dass der Rest trivialst ist.

ob dein pow korrekt funktioniert (ohne mit Inf als Ergebnis zu explodieren) hängt vom Wert von people ab.

Was willst eigentlich ausrechnen, Wahrscheinlichkeiten von gemeinsamen (Geburts-)Tagen?
Ergänzung ()

Im übrigen ist das ein wunderschönes Übungsbeispiel um es auch rein mit den eingebauten C++ - Boardmitteln (und dessen Typen), ohne Bibliotheken / externen Funktionen etc. vollkommen korrekt zum Laufen zu kriegen. Es geht nämlich auch mit stinknormalen 32-bit ints, doubles etc. Ich schreib daher nicht die ganze Lösung aus, sondern gebe pointer:

Erstens, man kann die Formel so umstrukturieren dass alle Subexpressions wohldefiniert sind und z.b. locker in einen double passen. Die Division der Fakultäten lässt sich etwa mathematisch so umschreiben dass nur mehr k Terme im Zähler übrigbleiben, mit k = der Wert von people. pow(365, k) hat ausgeschrieben auch genau k Einzeltermini. Wenn jetzt immer ein Term vom Fakultätsdivisionsrest mit einem vom pow zu einer Expression gepaart wird, multipliziert man am Schluss lauter Werte die alle in (0, 1] liegen. Einziges Problem ist wenn das Endergebnis so klein ist dass es sich dem epsilon vom Fliesskommatyp nähert, aber dafür muss people schon sehr gross sein.

Zweitens, man kann alles auf logarithmischer Skala rechnen und erst ganz am Schluss zum Endergebnis rückexponieren. Die ganze Formel besteht ja, wieder ausgeschrieben, nur aus Multiplikationen und Divisionen. Nun ist log((a*b) / (n^k)) nichts anderes als log(a) + log(b) - k*log(n), und nichts davon ist für einen double ein Problem, selbst für a/b/k/n = 365 (oder sogar noch viiiiiel höheren Werten). Wichtig ist dass bereits die Fakultäten und das pow selbst auf logarithmischer Basis errechnet werden. Dann die weiter zur logarithmischen Wahrscheinlichkeit verknüpfen, und erst die dann exponieren. Selbst wenn die gesuchte Endwahrscheinlichkeit extrem klein ist (z.B. < 1e-15) und es dann ungenau wird stimmt das Ergebnis auf log-Skala.

Natürlich kann man die Ansätze verknüpfen um es richtig robust und elegant zu machen. Also du wandelst wie im 1. Schritt gezeigt die Formel um, und die Expressionen dort rechnest du dann wiederum alle auf logarithmischer Basis zusammen.
 
Zuletzt bearbeitet:
Ist denn schon eine Logarithmusfunktion bei C++ mit an Bord? Das würde einem das Leben deutlich vereinfachen.

Ansonsten erstmal danke für die Antwort, dann habe ich ja schonmal einen Ansatz.
Du hast ganz recht, das Programm soll später, reagierend auf User-Input, die Wahrscheinlichkeit für gemeinsame Geburtstage angeben.

Das mit dem Logarithmus macht Sinn, mal gucken ob ich es hinbekomme sowas zu implementieren.

Beste Grüße,
TheShooter
 
Zurück
Oben