Forum: PC-Programmierung beliebig große Zahlen in C++


von Maxim (maxim) Benutzerseite


Lesenswert?

Ich habe folgendes Problem (stark vereinfacht): In einem Array 
exponents[] sind lauter Exponenten gespeichert. Diese haben einen 
Bereich von -1000 bis +1000 (und auch mehr). Die Aufgabe ist, diese 
Summe hier zu berechnen:
1
long double sum = 0;
2
for(int i = 0; i < N; i++) {
3
  sum += exp(exponents[i]);
4
}

Es kommt natürlich zum Überlauf in exp(). Der Witz ist, dass die Summe 
am Ende eine recht humane Zahl ist (also auf jeden Fall durch long 
double abgedeckt). Nur um auf diese Zahl zu kommen, muss man eben zuerst 
diese rießigen Exponenten verarbeiten. Ich habe in einem Buch gelesen, 
dass man den Umweg über den Logarithmus gehen kann, verstehe aber nicht 
im Detail, wie das umzusetzen ist. Gibt es hier schon Leute mit 
Erfahrung bei diesem Problem?

Alternativ könnte ich auf eine spezielle Bibliothek mit unbegrenzten 
Zahlen umsteigen, wenn es das gibt. Bisher kenne ich nur GMP, was eine 
Bibliothek für beliebige Genauigkeit ist. Ich weiß aber nicht, ob diese 
Bibliothek auch beliebig große Zahlen verarbeiten kann.

Nachtrag:
Die Formel für die Umgehung der Berechnung großer Exponenten lautet:
log(a + b) = log(a) + log(1 + exp(log(b) - log(a)))
Erwähnen muss ich noch, dass die Exponenten zwar einen großen Bereich 
haben können, in dem Array exponets[] aber immer nur relativ Ähnliche 
Exponenten gespeichert sind, z.B. 700 plus/minus 10. Wenn ich es richtig 
interpretiere, sind log(a) und log(b) also meine Exponenten und die 
Formel oben enthält zwar eine exp()-Funktion. Diese enthält aber die 
Differenz log(b) - log(a). Da diese Differenz in diesem Beispiel 
höchstens 2 * 10 ist, lässt sich log(a + b) ohne Überlauf berechnen und 
dadurch dann auch a + b = exp(log(a + b)).

Ist das so korrekt?

von Mathe (Gast)


Lesenswert?

Maxim S. schrieb:
> Es kommt natürlich zum Überlauf in exp(). Der Witz ist, dass die Summe
> am Ende eine recht humane Zahl ist (also auf jeden Fall durch long
> double abgedeckt)

Der eigentlich Witz ist noch viel besser: Wie soll bei nur positiven 
Ergebnissen für exp(-1000;1000) denn die Summe jemals kleiner sein als 
ein Einzelergebnis?

Und wie soll allein ein einziger Summand mit exp(700) in ein double 
passen?

von Mathe (Gast)


Lesenswert?

ok, es passt natürlich locker rein ;-) war gerade bei long int = 2^64 
bis 2^128 ;-)

von Stephan B. (matrixstorm)


Lesenswert?

Hi

Fuer beliebig grosse natuerliche, ganze und Festkommazahlen:

http://gmplib.org/

Gleitkomma:

http://www.mpfr.org/

von Maxim (maxim) Benutzerseite


Lesenswert?

MPFR sieht vielversprechend aus, vor allem mit ausführlicher 
Dokumentation. Danke.

von Reinhard Kern (Gast)


Lesenswert?

Maxim S. schrieb:
> Erwähnen muss ich noch, dass die Exponenten zwar einen großen Bereich
> haben können, in dem Array exponets[] aber immer nur relativ Ähnliche
> Exponenten gespeichert sind, z.B. 700 plus/minus 10.

Wenn das so ist, könntest du natürlich während der Summierung von allen 
Einträgen 690 abziehen (also ein fester Divisor) und dadurch mit 
entsprechend kleineren Zahlen rechnen. Bloss musst du dann zum Ergebnis 
diese 690 wieder dazurechnen (Multiplizieren).

M.a.W. du dividierst alle Eingangsdaten durch die kleinste vorkommende 
Zahl und multiplizierst am Ende die Summe wieder damit.

Gruss Reinhard

von ergänzung (Gast)


Lesenswert?

... und das am Ende zu addierende N*exp((min(Abs(exponents))) kannst du 
durch eine Multiplikationschleife bestimmen.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Maxim S. schrieb:
> muss man eben zuerst
> diese rießigen Exponenten verarbeiten.

Was bitte sind "rießige Exponenten"?

von Klaus W. (mfgkw)


Lesenswert?

Die sind wahrscheinlich aus Nördlingen?

von Kindergärtner (Gast)


Lesenswert?

Maxim S. schrieb:
> Der Witz ist, dass die Summe
> am Ende eine recht humane Zahl ist (also auf jeden Fall durch long
> double abgedeckt).
Hä? Also zu meiner Studienzeit sah die exp-Funktion noch so aus:
http://upload.wikimedia.org/wikipedia/commons/3/38/Exp_e.svg
Das heißt, sie ist überall > 0. Wenn du also "große" exp(x) hast und 
summierst, wird die Summe niemals kleiner und kommt immer weiter aus dem 
double-Bereich heraus, völlig egal ob du vorher irgendwas umstellst...

von Reinhard Kern (Gast)


Lesenswert?

Maxim S. schrieb:
> Der Witz ist, dass die Summe
> am Ende eine recht humane Zahl ist

Wie der Kindergärtner schon festgestellt hat kann die Summe grosser 
positiver Zahlen nicht kleiner als die Zahlen werden - das geht nur wenn 
sich positive und negative Summanden weitgehend aufheben. Nach deiner 
Beschreibung gibt es aber garkeine negativen Summanden.

Andrerseits schreibst du von Exponenten -1000 ... +1000. e ^-1000 ist 
aber keine negative, sondern eine sehr kleine Zahl. Da drängt sich der 
Verdacht auf, dass du die Aufgabenstelleung überhaupt nicht verstanden 
hast und die Daten eine ganz andere Bedeutung haben.

Gruss Reinhard

von Yalu X. (yalu) (Moderator)


Lesenswert?

Maxim S. schrieb:
> Die Formel für die Umgehung der Berechnung großer Exponenten lautet:
> log(a + b) = log(a) + log(1 + exp(log(b) - log(a)))

Wenn du schon diesen Tipp bekommen hast, warum wendest du ihn nicht 
einfach an?

Die Idee dahinter ist die folgende:

Reinhard Kern schrieb:
> Wenn das so ist, könntest du natürlich während der Summierung von allen
> Einträgen 690 abziehen (also ein fester Divisor) und dadurch mit
> entsprechend kleineren Zahlen rechnen. Bloss musst du dann zum Ergebnis
> diese 690 wieder dazurechnen (Multiplizieren).

Maxim S. schrieb:
> Ist das so korrekt?

Ja.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.