Programmierung des Logarithmus Naturalis mit der Programmiersprache C?

2 Antworten

Vom Fragesteller als hilfreich ausgezeichnet

Ich nehme an, dass es Dir hier um die Uebung geht und nicht unbedingt um Effizienz. Ich erlaeutere Dir den einfachsten Algorithmus, der mir einfaellt:

Grundlage: Der Logarithmus Naturalis (ln) laesst sich folgendermassen als Reihe darstellen:

ln(1-t) = - [ t/1 + t^2/2 + t^3/3 + t^4/4 + usw. ]    konvergent fuer t∈[-1,1)

Dies liefert die Werte des Logarithmus' auf dem Intervall (0,2], soweit bekannt?

Algorithmus (Beispiel): Deine Implementierung sollte den Logarithmus aber ja fuer alle positiven Zahlen bestimmen koennen. Wie man obige Formel trotz des eigenschraenkten Konvergenzbereichs verwenden kann, zeige ich Dir mal an einem Beispiel:

ln(42)
= ln(e^4 * 42/e^4)
= ln(e^4) + ln(42/e^4)
= 4 + ln(0.7692...)
= 4 + ln(1 - 0.2307...)
= 4 - [ 0.2307.../1 + 0.2307...^2/2 + 0.2307...^3/3 + usw. ]

Du schaust also zuerst, wie oft der Faktor e = 2.7182... in die gegebene Zahl passt - in diesem Fall ist e^3 noch kleiner als 42, e^4 ist erstmals groesser als 42. Daher laesst sich 42/e^4 = 1 - t schreiben fuer ein t∈(0,1). Je mehr Summanden Du mitnimmst, desto genauer wird Dein Resultat.

Hyperblue 
Fragesteller
 26.11.2017, 13:50

Soweit sehr gut erklärt! Wie würde aber nun die Funktion ausschauen, um diese Formel zu realisieren? 

0
BatesFan  26.11.2017, 15:27
@Hyperblue

Da Du nach der Programmiersprache C fragst, gehe ich davon aus, dass Du etwas Erfahrung im Programmieren hast, oder? Ich gebe Dir hier eine Implementierung mit drei kleinen Luecken <...> zum Ausfuellen - wenn Du das hinbekommst, hast Du das Programm verstanden:

#include <stdio.h>

// accepts a number t and an integer N and
// computes t + t^2/2 + t^3/3 + ... + t^N/N
double ln_series(const double t, const int N) {
// use Horner's method
double a = 0;
for (int i = N; i > 0; --i) {
a += <...>;
a *= t;
}
return a;
}

// accepts a positive number x and computes
// an approximation of ln(x)
double ln(const double x) {
// Euler constant
const double e = 2.7182818284590452;

// number of summands
const int N = 1000;

// rescale x
int c = 0;
double sc = 1.0;
while (<...>) {
++c;
sc *= e;
}

// compute ln(x)
return c - ln_series(<...>, N);
}

int main(void) {

// check ln(42) = 3.73767
printf("ln(%lf) = %lf\n", 42.0, ln(42.0));

return 0;

}

Zum Auswerten der Summe verwende ich das Horner-Schema, da es Multiplikationen spart und sich leicht programmieren laesst ( https://de.wikipedia.org/wiki/Horner-Schema#Verfahren ). Ansonsten geht's wie oben beschrieben.

1
Hyperblue 
Fragesteller
 26.11.2017, 18:06
@BatesFan

Kannst du es mir auch auf die herkömmliche Art, ohne das Horner-Schema erklären? Dies habe ich nämlich noch nicht behandelt. 

0
BatesFan  26.11.2017, 18:17
@Hyperblue

Naja, die Funktion ln_series(t, N) soll wie im Kommentar beschrieben eben die Summe

t + t^2/2 + t^3/3 + ... + t^N/N

berechnen. Ob Du das mit oder ohne Horner-Schema machst, ist ja egal. Du kannst meine Funktionsdefinition durch eine eigene ersetzen! Schreibe eine for-Schleife, die nach und nach die einzelnen Summanden hinzufuegt:

double a = 0;
for (int i = 1; i <= N; ++i) {
// addiere t^i / i zu a
<...>
}

Isendrak hat Dir ja gezeigt, wie Du die Potenzen t^i berechnen koenntest. Eine Summe zu berechnen ist eigentlich eine sehr grundlegende Aufgabe... Welche Programmiererfahrung hast Du denn bisher?

0

Verwende den Logarithmus in Form einer Potenzreihe: https://de.wikipedia.org/wiki/Logarithmus#Als_Potenzreihe

Für die Potenzen kannst du dir auch eine einfache Funktion basteln, wie z.B.:

double pow(double x, int y){
double p = x;
for(int i = 1; i < y; ++i) p *= x;
return p;
}