beliebig große Zahlen in C++

OP Persönliche Seite #3302574
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?
Gast #3302580
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?
Gast #3302605
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
Gast #3303120
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...
Gast #3303375
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
Moderator #3303785
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren