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?