Logarithmus

Berechnung mit Reihen-Entwicklung

Logarithmus und Exponential sind wichtige Funktionen, u.a. weil sich damit viele aufwändige Rechnungen um eine Stufe vereinfachen. Wenn diese Funktionen nicht zur Verfügung stehen, dann kann man sie mit Reihen-Entwicklungen selbst programmieren. Unabhängig davon sind die Beispiele für die Ausbildung gut brauchbar, weil man die Ergebnisse jederzeit durch Vergleich mit den Standard-Funktionen kontrollieren kann.
Algorithmen Ausgewählte IT-Rezepte, Iterationen
Log-Funktion Die Ln() und Log()-Funktionen und ihre Anwendung in der Informatik
Anwendung Multiplikation, Division, Potenzierung, Wurzeln, ...
Programmierung Die Log-Funktion in Programmen und Programmiersprachen
Log-Reihe Reihen-Entwicklung der Log-Funktion mit Live-Beispiel
Log-Algorithmus Anpassung des Log-Algorithmus
Log-Optimierung Optimierung des Log-Algorithmus
Basic Log-Funktion mit LibreOffice-Basic, Visual Basic (VBA)
Javascript Log-Funktion mit Javascript (z.B. Live in Webseiten)
Hilfs-Funktionen Potenz-Funktion, Fakultät - nur mit den 4 Grundrechnungs-Arten
Verwandte Themen Exponential-Funktion, Euler'sche Zahl e=2.71828...

Logarithmus

Der Natürliche Logarithmus ist jene Zahl y, mit der man die Basis e potenzieren muss, um eine Zahl x zu erhalten:
x = e^y
ln(x) = y
Die Umkehrung kann man als Potenzierung (hier mit dem Operator ^ bezeichnet) oder mit Hilfe der → Exponential-Funktion beschreiben:
x = exp(y)

Als Basis wird die konstante → Euler'sche Zahl e=2.71828... verwendet. Das ergibt zwar keine anschaulichen Werte, man kann damit jedoch besonders gut rechnen.

Der Funktions-Name wird meist LN, selten mit LOG abgekürzt.

Der natürliche (und jede andere Logarithmus) ist nur für positive Zahlen>0 definiert, d.h. ln(0) oder ln(-1) ergeben Fehler.
Sonderfall:
ln(1) = 0

Beispiele:
ln(1/2) = -0.693147180559945
e^-0.693 = 2.718^-0.693 = 0.5

ln(2) = 0.693147180559945
e^0.693 = 2.718^0.693 = 2

ln(10) = 2.30258509299405
e^2.3026 = 2.718^2.3 = 10
Der Dekadische Logarithmus ist jene Zahl y, mit der man die Basis 10 potenzieren muss, um eine Zahl x zu erhalten:
x = 10^y
log10(x) = y

Die Zahl 10 als Basis ergibt anschauliche Werte. Deshalb wurde der dekadische Logarithmus in der Vor-Computer-Zeit von TechnikerInnen häufig verwendet.

Umrechnung   natürlicher ↔ dekadischer Logarithmus:
log10(x) = ln(x) / ln(10)
ln(x) = log10(x) * ln(10)
Umrechnungs-Faktor:
ln(10) = 2.30258509299405

Beispiele:
log10(0.01) = -2
log10(0.1) = -1
log10(0.5) = -0.301029995663981
log10(1) = 0
log10(2) = 0.301029995663981
log10(e) = 0.434294481903252
log10(10) = 1
log10(100) = 2
log10(1000) = 3
Der Allgemeine Logarithmus verwendet eine beliebige positive Zahl b>0 als Basis. Andere Basis-Werte als b=e=2.718 oder b=10 haben jedoch geringe Bedeutung.
Umrechnung:
log(b,x) = ln(x) / ln(b)
ln(x) = log(b,x) * ln(b)
Der allgemeine Logarithmus ist die Umkehrung der allgemeinen Potenz-Funktion:
y = pow(b,x) = b^x
x = log(b,y)
b = y^(1/x)
Der Begriff y^(1/x) wird auch x-te Wurzel aus y bekannt.

Beispiele des allgemeinen Logarithmus mit der Basis b=2
log(2, 1/4) = -2
log(2, 1/2) = -1
log(2, 0) = 0
log(2, 2) = 1
log(2, 4) = 2
log(2, 8) = 3
2^3 = 8

Ähnlichkeit

Die Diagramme aller Logarithmus-Funktionen ln(), log10(), log(b,*) mit Basis 1>b sind einander ähnlich (so wie ↑ oben gezeigt), d.h. man kann sie durch Multiplikation der ln() Funktion mit einem konstanten Faktor erhalten.
Diese Eigenschaft verwendet man zur Berechnung von Logarithmen mit beliebiger Basis mit Hilfe der fast immer verfügbaren ln() Funktion. (allgemeiner ↑ Logarithmus)

Spiegelung

Die Diagramme aller Logarithmus-Funktionen mit Basis 1<b erscheinen an der X-Achse gespiegelt.
Daraus ergeben sich einige wichtige Eigenschaften der Funktion:
ln(x) = -ln(1/x)
allgemein
log(b,x) = -log(1/b,x)
log(b,x) = -log(b,1/x)
log(b,x) = log(1/b,1/x)

Binär-System

Einige wichtige Daten der Informatik kann man mit Potenzen und Logarithmen berechnen:

Anzahl der mit b Bit darstellbaren positiven ganzen Zahlen d:
d = 2^b
Beispiele:
1 Byte: 2^8  = 256
2 Byte: 2^16 = 65536
4 Byte: 2^32 = 4.295E+9
8 Byte: 2^64 = 1.845E+19
Um auch negative ganze Zahlen darzustellen, braucht man 1 Bit für das Vorzeichen (Details zum → 2er-Komplement):
1 Byte: 2^(8-1)  von -128   bis +127
2 Byte: 2^(16-1) von -32768 bis +32767
Die Zahl 2^32 = 4.3E+9 wurde bekannt, weil damit die 4GB-Grenze von 32-Bit PC-Systemen erreicht wurde.

Umkehrung: Anzahl der benötigten Bits b zur Darstellung einer positiven ganzen Dezimalzahl d:
b = ln(d) / ln(2)
Beispiele:
100:       ln(100)/ln(2)  = 6.6
256:       ln(256)/ln(2)  = 8.0
1000:      ln(1000)/ln(2) = 9.97
Million:   ln(1E+6)/ln(2) = 19.9
Milliarde: ln(1E+9)/ln(2) = 29.9
Da es nur ganze Bits gibt, muss man die berechnete Anzahl b immer aufrunden, um die angegebene Dezimalzahl d darzustellen:
b = int(ln(d) / ln(2) + 0.5)

Gleitkomma-Zahlen werden in allen gängigen Programmen und Programmiersprachen ohne besondere Maßnahmen mit dem Typ Double Precision gespeichert.

Für diesen Typ werden 8 Byte = 64 Bit Speicherplatz verwendet, davon 53 Bit für die binäre Mantisse und 11 Bit für den binären Exponenten.

Die binäre Mantisse bestimmt die Genauigkeit (Auflösung) der Zahlen: 2^53 = 9E+15, d.h. die mit 53 Bit erreichbare Genauigkeit beträgt ca. 15..16 Dezimalstellen.
Test mit einem Kalkulations-Programm oder mit Double Precision-Variablen einer beliebigen Programmiersprache:
Berechnen sie
y15 = 1.0E+15 + 1
y16 = 1.0E+16 + 1
und danach die Differenzen
y15 - 1.0E+15 = 1
y16 - 1.0E+16 = 0
Das Beispiel zeigt, dass die relative Änderung einer beliebigen Zahl um 1E-16 ihres Wertes (= nach der 15. Dezimalstelle) nicht mehr darstellbar ist.
Die erreichte Genauigkeit ist das wichtigste praktische Kriterium für den Abbruch einer Reihen-Entwicklung:
Man berechnet die Differenz zwischen dem Ergebnis r einer Schleife und dem Ergebnis rv der vorhergehenden Schleife:
dr = r - rv
Das Ergebnis ist damit ca. auf ln(dr)/ln(10) Dezimalstellen genau.

Der binäre Exponent bestimmt die minimale und maximale Größe von Gleitkomma-Zahlen. Mit 11 Bit sind ganze Zahlen bis d=2^11=2048 darstellbar, oder von -1024 bis +1023
Mit diesen binären Exponenten und der maximalen Mantisse ergibt sich
z(min) = 2^-1024 = 1.7977E-308
z(max) = 2^1024  = 1.7977E+308

Hexadezimal (16er)-System

Zur anschaulichen Darstellung von binären Daten verwendet man oft das Hex-System mit den 16 Ziffern 0...9,A...F
Zur Darstellung von je 4 Bit verwendet man genau 1 Hex-Ziffer, da 2^4=16
Für jedes darzustellende Byte braucht man genau 2 Hex-Ziffern, daher ist jedes Byte mit den Zahlen 0x00 bis 0xFF (anders dargestellt #00...#FF) darstellbar.

Anzahl der mit h Hex-Ziffern darstellbaren positiven ganzen Zahlen:
d = 16^h
Anzahl der zur Darstellung einer ganzen Dezimalzahl d benötigten Hex-Ziffern:
h = ln(d) / ln(16)
Auch in diesem Fall muss man das Ergebnis h auf ganze Hex-Ziffern aufrunden.

Anwendung der Logarithmus-Funktion

Eine klassische Anwendung des Logarithmus ist die Vereinfachung schwieriger Rechnungen. Dabei werden immer die beiden Funktionen ln() und exp() kombiniert, die einander umkehren.
Die Wirkung wird oft so formuliert, dass mit dem Logarithmus die 'Rechnungs-Stufe' herabgesetzt wird: Aus einer Multiplikation wird eine Addition, aus einer Division eine Subtraktion, usw.
In der Informatik spielen diese Methoden auf Prozessor-Ebene eine wichtige Rolle:
Dort gibt es keine mathematischen Funktionen, in sehr einfachen Prozessoren nicht einmal Multiplikation oder Division. Mit Hilfe der Logarithmus-Funktion kann man auch Rechnungen einer 'höheren' Stufe ausführen.
Sowohl die Logarithmus-Funktion als auch die → Exponential-Funktion lässt sich durch ↓ Reihen-Entwicklung berechnen.

Multiplikation   x*y

Die Multiplikation wird auf eine Addition der Logarithmen zurückgeführt.
ln (x * y) = ln(x) + ln(y)
Man berechnet die Logarithmen der Argumente x und y, addiert diese und bestimmt das Exponential der Summe:
x * y = exp(ln(x) + ln(y))

Das erscheint heute als Umweg, war jedoch lange Zeit hindurch die Grundlage vieler praktischer und zeitsparender Methoden und Geräte, z.B. des Rechenschiebers. Wenn einmal für längere Zeit der Strom ausfallen sollte, wird man sich daran erinnern...

Beispiel:
123 * 456 = exp(4.812 + 6.122) = exp(10.935) = 56088

Diese Methode wird verwendet, um den Algorithmus zur Berechnung des Logarithmus sehr kleiner Argumente x zu beschleunigen:
ln(x * 2) = ln(x) + ln(2)
Eine beliebige kleine Zahl x<0.5 wird so oft verdoppelt, bis 0.5<=x<1 ist. Das kostet zwar Rechenzeit, spart jedoch meistens wesentlich mehr durch die raschere Ausführung des ↓ Reihen-Algorithmus.

Division   x/y

Funktioniert ähnlich wie die Multiplikation. Sie wird auf eine Subtraktion der Logarithmen zurückgeführt:
ln(x / y) = ln(x) - ln(y)
x / y = exp(ln(x) - ln(y))

Beispiel zur Halbierung einer beliebigen Zahl x
ln(x / 2) = ln(x) - ln(2)
x / 2 = exp(ln(x) - ln(2)) = exp(ln(x) - 0.693)

Diese Methode wird verwendet, um Argumente 1>x in den Bereich 0<=x<1 zu transformieren:
ln(1 / x) = ln(1) - ln(x) = -ln(x)
weil ln(1)=0 ist. Die Umwandlung ist notwendig, weil der ↓ Reihen-Algorithmus nur Argumente 0<=x<1 berechnen kann.

Potenzierung   x^y

Die Potenzierung wird auf eine Multiplikation zurückgeführt:
ln(x^y) = ln(x) * y
x ^ y = exp(ln(x) * y)

Beispiel:
2 ^ 10 = exp(0.693 * 10) exp(6.931) = 1024

Die Potenzierung mit kleinen ganzzahligen Exponenten y berechnet man meist schneller in einer Schleife:
x^3 = x * x * x
für Gleitkomma-Exponenten ist die Verwendung des Logarithmus jedoch die Standard-Methode.

Wurzeln   x^(1/x)

Das Wurzelziehen wird auf eine Division zurückgeführt:
ln(x^(1/y)) = ln(x) / y
x ^ (1/y) = exp(ln(x) / y)
Für die Quadratwurzel wird
sqr(x) = x ^ (1/2) = exp(ln(x) / 2)

Beispiel: 3. Wurzel aus 100
100^(1/3) = exp(4.605 / 3) = exp(1.535) = 4.642

Zur Berechnung einfacher ganzzahliger Wurzeln (Quadratwurzel, Kubikwurzel, ...) verwendet man besser die darauf spezialisierten → Reihen-Algorithmen.
Gleitkomma-Wurzeln werden nur selten gebraucht, in diesem Falle verwendet man die Division des Logarithmus als Standard-Methode.

Genauigkeit

Wenn man Logarithmen verwendet, um die 'Rechnungs-Stufe' herabzusetzen, dann kann sich dabei die Genauigkeit verringern. Es hängt von der jeweiligen Rechnung (Formel, Algorithmus) ab, wie stark sich ein Fehler von +/-1 der letzten Stelle auf das Ergebnis auswirkt.

Test: Wenn sie in einer Rechnung y=ln(x) verwenden, dann rechnen sie probeweise auch mit yerr=y*(1+1/1E15)
Die Differenz der beiden Ergebnisse ergibt die ungefähre Genauigkeit (numerische Auflösung) ihrer Rechnung.
Beispiel
Die hier vorgestellte Methode wird u.a. auf dieser Seite zur Beschleunigung eines Algorithmus (Berechnung des ↓ natürlichen Logarithmus) verwendet. Dabei wird eine (mehrfache) Multiplikation auf die (mehrfache) Addition eines Logarithmus zurückgeführt.

Eine Zahl x>1 wird durch fortgesetzte Halbierung in einen optimalen Werte-Bereich gebracht, hier z.B. durch 4malige Division durch 2 (das lässt sich binär besonders rasch ausführen):
x = 12
a = x = 12
a = a/2 = 6
a = a/2 = 3
a = a/2 = 1.5
a = a/2 = 0.75

Nun kann man den natürlichen Logarithmus durch ↓ Reihen-Entwicklung einfach und rasch berechnen:
b = ln(a) = -0.288

Um den Logarithmus der Zahl x zu erhalten, wird 4mal der Logarithmus des vorher (links) verwendeten Divisors 2 addiert:
ln(2) = 0.693
b = b + ln(2) = 0.405
b = b + ln(2) = 1.099
b = b + ln(2) = 1.792
b = b + ln(2) = 2.485

Damit hat man das Ergebnis berechnet - scheinbar auf Umwegen, tatsächlich jedoch besonders schnell:
ln(x) = b = 2.485

Logarithmische Skalen

Manchmal ist es notwendig, Zahlenwerte eines besonders großen Werte-Bereichs darzustellen. Dazu verwendet man am besten eine logarithmische Skala.
Eine logarithmische Skala zeigt sowohl sehr kleine als auch sehr große Zahlenwerte gleichzeitig an. Allerdings sind nicht alle Menschen in der Lage, eine logarithmische Skala sinnvoll zu interpretieren. Pisa- und andere Tests legen das nahe.
Quelle: Wikipedia
Beispiel: Der römische Bürger Mercatorius legt im Jahr 1 einen Aureus (röm.Goldmünze) bei der Bank von Rom an. Die Bank verzinst die Einlage mit jährlich 3%.
1 Aureus = 8.19g Gold (Au)

Wenn Mercatorius das Geld nicht abhebt, sondern seinen Nachkommen vererbt, dann hätte die Bank zunächst keine Probleme, das angesparte Kapital in Gold aufzubringen: Nach 100 Jahren hätte der Wert lediglich 157g betragen, nach 163 Jahren immerhin schon 1kg und nach 396 Jahren 1 Tonne Gold.

Das angesparte Kapital in Gold, als 'gewöhnliches' (=lineares) Diagramm. Der Wert nach 1000 Jahren beträgt 5.63E+13 g. Die vertikale Skala zeigt das angesparte Kapital in Mt (Megatonnen = Mio t) Gold. Im linearen Maßstab kann man nur die großen Zahlenwerte erkennen. Die kleinen Zahlenwerte der ersten 600 Jahre sind in diesem Maßstab nicht erkennbar (Rechtsklick in das Diagramm | Quelltext zeigt die Daten an).

Dieses Diagramm zeigt die gleichen Daten an, die vertikale Achse ist jedoch im logarithmischen Maßstab angelegt. Man kann nun alle Daten gut erkennen, auch die kleinen Zahlenwerte. Die großen Zahlenwerte werden allerdings weniger genau angezeigt.
Wenn das römische Reich nicht rechtzeitig untergegangen wäre, dann hätte die Bank allerdings zunehmende Probleme mit den Urenkeln von Mercatorius bekommen:
Im Jahre 630 wären bereits 1000t Gold zu beschaffen, im Jahr 864 1 Mio t Gold.
Wenn die Bank alles Gold der Erdkruste bis in eine Tiefe von 4km fördern ließe, dann hätte das theoretisch bis 1661 gereicht. Im Jahre 1944 wäre die Masse des Mondes in Gold fällig gewesen, im Jahre 2093 die Masse der gesamten Erde.
Wie man sieht, kann ein derartiges System nur für begrenzte Zeiten funktionieren. Langfristig muss es (wie bei jedem Pyramidenspiel) zu einem Kollaps kommen, weil es keine beliebig großen Werte gibt. Das System lässt sich länger erstrecken, wenn die laufende Entwertung größer als der durchschnittliche Zins-Ertrag ist. Irgendwann reicht das nicht mehr aus, und dann werden im Rahmen einer 'Wirtschaftskrise' größere Werte pauschal vernichtet. Nur die SchülerInnen der Grundschule glauben noch daran, dass sich ihr Taschengeld auf einem Sparbuch auf wunderbare Weise vermehren kann.

Logarithmus-Funktion in Programmen & Programmiersprachen

Natürlicher Logarithmus

Tabellen-Kalkulation (LibreOffice_Calc, OpenOffice-Calc, MS-Excel, ...):
=LN(A1)

C/C++: Bibliothek
#include <math.h>
Funktion
double log(double x);
C++ bietet zusätzlich überladene Varianten für die Typen float, long double, complex, ...
Diese Preprocessor-Makros sind meist definiert, werden jedoch als 'system-spezifisch' angegeben:
M_LOG2E = 1.4426950408889634074
M_LOG10E = 0.43429448190325182765
M_LN2 = 0.69314718055994530942
M_LN10 = 2.30258509299404568402

Javascript Konstanten:
Math.LN2 = 0.693147180559945
Math.LN10 = 2.30258509299405
Funktion:
y=Math.log(x);

Perl Funktion:
y=log(x);

PHP Konstanten:
M_LN2 = 0.69314718055994530942
M_LN10 = 2.30258509299404568402
Funktionen:
y=log(x);
yp=log1p(x)=log(x+1);
log1p() berechnet ln(1+x) auch für sehr kleine x rasch und genau.

Basic (LibreOffice-Basic, VBA):
y=Log(x)

XSL kennt leider keine Logarithmus-Funktion. Man kann mit Reihen-Entwicklung eine eigene Funktion programmieren, um z.B. Diagramme mit logarithmischen Skalen zu erzeugen.

Dekadischer Logarithmus

Kalkulation (LibreOffice_Calc, OpenOffice-Calc, MS-Excel, ...):
=LOG(A1)

Der dekadische Logarithmus wird heute kaum mehr verwendet. Nur wenige Programmiersprachen bieten dafür eigene Funktionen:

C/C++: Bibliothek
#include <math.h>
Funktion
double log10(double x);
C++ bietet zusätzlich überladene Varianten für die Typen float, long double, complex, ...

PHP Funktion:
y=log10(x);

Basic (LibreOffice-Basic, VBA) :
y=Log10(x)

In jedem anderen Fall berechnet manlog10(x)=ln(x) / ln(10) mit Hilfe des natürlichen Logarithmus.
LibreOffice - Kosten- und lizenzfreie Office-Programme (inkl. Kalkulation) für alle gängigen Betriebssysteme und Sprachen, kompatibel mit MS-Excel.
Java - Programmiersprache von Sun / Oracle, kostenfrei für alle gängigen Systeme. Home
Javascript - Programmiersprache, in jedem gängigen Browser-Programm integriert.
Perl - Programmiersprache, in jeder Linux_Distribution kostenfrei enthalten, für Windows kostenfrei bei ActiveState
PHP - Programmiersprache, kosten- und lizenzfrei für alle gängigen Systeme. Home: php.net
Basic (VBA) - Programmierrsprache von Microsoft oder als OpenSource-Version, in jedem gängigen Kalkulations-Programm (OpenOffice, LibreOffice, Excel) integriert.
Wikipedia: Logarithmus, Exponential, Euler'sche Zahl, Taylor-Reihe, Reihe, Potenzreihe,
Formelsammlung: Reihenentwicklungen

Logarithmus-Funktion als Potenzreihe

Zur Berechnung des natürlichen Logarithmus verwendet man diese Reihe:

Quelle: Wikipedia

Dieser Algorithmus gilt nur für 0<x<1
Für x<0 ist die Logarithmus-Funktion selbst nicht definiert.
Der Wert ln(1)=0 wird nicht berechnet, sondern direkt angegeben.
Argumente 1>x muss man zuerst in den Bereich des Algorithmus transformieren, danach werden sie berechnet, so wie angegeben.
Zur numerischen Berechnung kann man den Algorithmus jedoch wesentlich einfacher formulieren:
b = (1-x)
ln (x) = - [b + b^2/2 + b^3/3 + b^4/4 + ...]
Diese Form erspart die Berechnung des alternierenden Vorzeichens und verwendet nur die Addition (= die schnellste der 4 Grundrechnungs-Arten).

Algorithmus:

Man braucht einen Zähler, hier mit n bezeichnet:
n = 1, 2, 3, 4, ...

Mit jedem Zähler-Wert berechnet man ein Element der Reihe
element[n] = b^n/b

Der Anfangswert einer Summen-Variablen wird mit sum=0 festgelegt. Unmittelbar nach seiner Berechnung wird jedes Element zur 'laufenden Summe' addiert:
sum = 0
sum = sum + element[1]
sum = sum + element[2]
sum = sum + element[3]...

Die Reihe wird (in der Standard-Version) so lange fortgesetzt, bis sich sie laufende Summe sum nach Addition eines sehr kleinen element's nicht mehr ändert.

Das Ergebnis ist
ln(x) = -sum

Kalkulations-Programm

Der Algorithmus lässt sich mit jeder Tabellen-Kalkulation relativ einfach programmieren:
Das Argument 0<x<1 wird in Zelle B1 eingetragen.
Die Hilfs-Variable b wird in Zelle B4 berechnet.
Im Bereich A7:A26 wird der Zähler n berechnet.
Die ersten 20 Elemente werden im Bereich B7:B26 berechnet, die laufende Summe im Bereich C7:C26
Das theoretische Ergebnis wird (zum Vergleich) mit der Standard-Funktion in B2 berechnet.
Das Ergebnis der Reihen-Entwicklung wird darunter in Zelle B3 angegeben.
   ABC
1Zahl x 0.864 
2ln(x) ==LN(B1) 
3myln(x) = =-C26 
4b=1-B1 
5 
6nElementSumme
71=$B$4^A7/A7=B7
8=A7+1=$B$4^A8/A8=C7+B8
9=A8+1=$B$4^A9/A9=C8+B9
...
26=A25+1=$B$4^A26/A26=C25+B26
Der Algorithmus ist stark vom Zahlenwert des Arguments 0<x<1 abhängig: Das Ziel wird für große x (nahe 1) rasch erreicht, für kleine x (nahe 0) dagegen sehr langsam.

Das Diagramm zeigt, wie viele Iterations-Schritte (Y-Achse) man ungefähr braucht, um eine gewünschte Genauigkeit zu erreichen.
Die Genauigkeit des Ergebnisses wird hier für 5 Dezimal-Stellen ( blau), 10 Stellen ( violett) und 15 Stellen (rot) angezeigt.
Die Genauigkeit von Standard (Double Precision) Gleitkomma-Zahlen beträgt 15-16 Dezimalstellen. Die rote Kurve markiert daher die Grenze für Kalkulations-Programme und Programmiersprachen (ohne besondere Variablen-Typen).
Die Daten wurden empirisch gewonnen und geglättet. Sie sind lediglich Richtwerte !

Beispiel: Für ein Argument x=0.6 braucht man ca. 10 Schritte, um den Logarithmus auf 5 Ziffern genau zu berechnen, 24 Schritte für 10 Ziffern oder 38 Schritte für 15 Ziffern.

Im Kapitel ↓ Optimierung wird gezeigt, wie man dieses Verhalten ausnützen kann, um rascher zu rechnen: Man transformiert alle 0<x<0.5 in den Bereich 0.5<x<1 wo man den Logarithmus mit wesentlich weniger Schritten berechnen kann.

Anzahl der Iteratios-Schritte als Funktion des Arguments bei der iterativen Berechnung der Funktion y = ln(x)

Anpassung des Algorithmus

Der oben angegebene Reihen-Algorithmus gilt nur für Argumente im Bereich 0>x<1 Für alle anderen Argumente x>1 nutzt man diese Eigenschaft der Logarithmus-Funktion:
ln(x) = -ln(1/x)
und bringt damit beliebige Argumente x>1 in den berechenbaren Bereich.

Hilfs-Variable

Alle hier vorgestellten Beispiele verwenden die beiden
Hilfs-Variablen a und v

Vor Beginn des einfachen Reihen-Algorithmus wird das Argument in den berechenbaren Bereich transformiert:

Für x<1:   a = x;     v = 1;
Für x>1:   a = 1/x    v = -1;

Mit a wird der Logarithmus berechnet, in der Variablen v merkt man sich, ob das Argument x transformiert wurde oder nicht.

Der Reihen-Algorithmus wird so berechnet wie ↑ oben vorgestellt:
b = (1-x)
sum = [b + b^2/2 + b^3/3 + b^4/4 + ...]

Nach dem Abbruch der Schleife wird das Vorzeichen des Ergebnisses je nach der Vorgeschichte umgekehrt:

Optimierung des Algorithmus

Ansatzpunkt ist das bei Vorstellung des ↑ einfachen Reihen-Algorithmus gezeigte Diagramm:

Jeder Schleifen-Durchgang kostet ungefähr die gleiche Rechenzeit. Man kann durch Verringerung der Schleifen-Anzahl viel Zeit sparen.
Andererseits kostet es Zeit, um mit zusätzlichen Maßnahmen das Argument vor Beginn des Schleifen-Algo in den optimalen Bereich nahe an x<1 zu bringen.
Faustregel:
Bei geringer Anforderung an die Genauigkeit (Mess- und Regeltechnik, Mikroprozessoren) ist eine Optimierung - wenn überhaupt - nur bei sehr kleinen x<0.1 sinnvoll.
Bei Standard-Genauigkeit (15 Dezimalstellen) ist eine Optimierung bei x<0.5 meist sinnvoll.

Es hängt vom durchschnittlichen Werte-Bereich der Argumente x ab, ob und welche Optimierung sich lohnt. Sie sollten Live-Tests ausführen, wenn die Rechenzeit kritisch ist.

Optimierung:

Der Algorithmus rechnet für Argumente 0.5...x...1 angenehm rasch. Leider wächst die Anzahl der Iterationen und die Rechenzeit mit wesentlich kleineren oder größeren Argumenten sehr rasch.
Man kann sich mit fortgesetzter Halbierung großer Argumente x helfen:
ln(x) = ln(x/2) + 1 * ln(2)
ln(x) = ln(x/4) + 2 * ln(2)
ln(x) = ln(x/8) + 3 * ln(2)
usw. bis x<1
Für sehr kleine Argumente gilt umgekehrt:
ln(x) = ln(2*x) - ln(2)

Lösung:
Man zählt, wie oft man das Argument x halbieren (oder verdoppeln) muss, um 0.5...x...<1 zu erhalten. Danach wird (rasch) ln(x) berechnet und ln(2) genauso oft addiert (subtrahiert), wie man vorher halbieren (verdoppeln) musste.
Ein weiterer Vorteil ist, dass die Halbierung oder Verdoppelung im intern verwendeten → Binärsystem besonders rasch funktioniert.

Logarithmus-Funktion mit Basic (LibreOffice-Basic, Visual Basic VBA)

Programmierung mit Basic (LibreOffice-Basic, Visual Basic VBA)


Argumente:
Die Funktion my_ln() akzeptiert 2 Argumente:
x ... Zahl, deren natürlicher Logarithmus zu berechnen ist
nmax ... Maximale Anzahl der zu berechnenden Elemente. Wenn nmax nicht angegeben wird, dann rechnet das Programm bis zur maximalen Genauigkeit ≈ auf 15 Dezimalstellen.

Hilfs-Variable:
a,b ... so wie oben beschrieben

Vorbereitung:
In 2 While-Schleifen wird a so lange verdoppelt oder halbiert, bis 0.5<=a<1 ist.
Die Variable h zählt die Anzahl der Verdoppelungen bzw. Halbierungen.

Anfangswerte:
doloop ... Schalter, steuert entweder die weitere Berechnung oder den Abbruch
ve ... Vorzeichen des jeweiligen Elements
sum ... Ergebnis der Reihen-Entwicklung (laufende Summe der berechneten Elemente)
n ... Zähler für die Elemente (Schritte)

Schleife
In jedem Schleifen-Durchlauf wird 1 Element berechnet.
element ... Das in der jeweiligen Schleife berechnete Element der Reihe

Abbruch:
Das jeweils vorige Ergebnis sumv wird mit dem aktuellen Ergebnis sum verglichen: Wenn keine Änderung erfolgt ist, oder wenn der Zähler seinen Maximalwert erreicht hat, dann wird doloop=False gesetzt und damit die Schleife abgebrochen.

Abschluss
Nach Abbruch der Schleife wird die Summe sum mit dem Vorzeichen v multipliziert und als Ergebnis zurückgegeben.

Vereinfachung:
Die Sonderfälle x<=0 (ergibt Fehler) und x=1 (ergibt die ↓ Euler-Zahl) werden im Beispiel nicht berücksichtigt.

Hilfs-Funktion:
Eine Reihen-Entwicklung ist dann sinnvoll, wenn man dafür keine anderen Funktionen benötigt. Daher wird an Stelle des Potenz-Operators (b^n) die ↓ Hilfs-Funktion my_pow() verwendet: Damit ist der gesamte Algorithmus mit den 4 Grundrechnungs-Arten durchführbar.

Vereinfachung: Der Sonderfall x=1 wird in dieser Version nicht berücksichtigt.

Reihen-Entwicklung der Logarithmus-Funktion als Basic-(VBA)-Funktion (vereinfacht):
Const LN2 = 0.693147180559945

Function my_ln( _
x As Double, _
Optional nmax As Integer = -1) _
As Double
Dim doloop As Boolean
Dim h, ve, n As Integer
Dim a, b, element, sum, sumv As Double
If nmax < 0 Then nmax = 1000
' If IsMissing(nmax) Then nmax = 1000 ' Vorbereitung
h = 0
a = x
While a < 0.5
a = a * 2
h = h - 1
Wend
While a > 1
a = a / 2
h = h + 1
Wend
' Anfangswerte
b = a - 1
n = 1
ve = 1
sum = 0
doloop = True
' Berechnungs-Schleife
While (doloop)
sumv = sum
' element = ve * b ^ n / n
element = ve * my_pow(b, n) / n
sum = sum + element
n = n + 1
If (sum=sumv Or n>=nmax) Then doloop = False
ve = ve * -1
Wend
my_ln = sum + h * LN2
End Function

Private Function my_pow( _
ByVal number As Double, _
ByVal exponent As Integer) _
As Double
Dim i As Integer
Dim p As Double
p = 1
For i = 1 To exponent
p = p * number
Next
my_pow = p
End Function
Anwendung
Man kann das Basic-Programm als 'Benutzerdefinierte Funktion' in jedem Kalkulations-Programm verwenden. Zur Berechnung bis an die Grenze der Genauigkeit geben sie z.B. diese Formel ein:
E2=my_ln(B1)
(Annahme: Das Argument x befindet sich in Zelle B1 )

Zur Berechnung einer begrenzten Anzahl von Elementen geben sie z.B. diese Formel ein:
E7=my_ln($B$1;A7)
Diese Formel kann man nach unten ausfüllen. Das Ergebnis sollte gleich oder sehr ähnlich jenem des Kalkulations-Programms in Spalte D sein.

Logarithmus-Funktion mit Javascript

Programmierung mit Javascript

Die Funktion ist im Quelltext dieser Webseite enthalten und rechnet Live, wenn sie den Button klicken:


Elemente


Live-Ergebnis:
Argument  x = ?
my_ln(x)    = ?
ln_theor(x) = ?
Genauigkeit ≈ ? Dezimalstellen
Anzahl der Iterationen = ?
Rechenzeit = ? µs

Der Sonderfall x=1 wird nicht mit Reihen-Entwicklung berechnet, sondern direkt das Ergebnis ln(1)=0 zurückgegeben.
Reihen-Entwicklung der Logarithmus-Funktion als Javascript-(JS)-Funktion.
function my_ln(x,nmax) {
if(x==1) {return 0;}
else{
if(nmax<0) {nmax=1000;}
var a=x; var h=0;
while(a<0.5) {a*=2; h--;}
while(a>1) {a/=2; h++;}
var b = a - 1;
var sum=0; var sumv=0;
var ve=1; var element=0;
var n = 1;
var doloop = true;
while(doloop) {
sumv = sum;
element = ve * my_pow(b,n) / n;
sum += element;
n++;
if(sum==sumv || n>=nmax) {doloop=false;}
ve *= -1;
}
return sum + h * Math.LN2;
}
}

Hilfs-Funktionen

Die meisten Programmiersprachen bieten mindestens einige grundlegende mathematische Funktionen. Sie sind entweder in der Grundausrüstung enthalten oder werden als Modul (Bibliothek...) bei Bedarf eingebunden. Wenn jedoch die benötigten Funktionen fehlen, oder - wie bei einfachen MikroProzessoren - überhaupt keine mathematischen Funktionen verfügbar sind, dann muss man eigene Funktionen programmieren, welche ausschließlich die 4 Grundrechnungs-Arten (Addition, Subtraktion, Multiplikation, Division) verwenden.

Potenz-Funktion

Diese Funktion ist je nach Programmiersprache als Funktion (meist unter Namen wie pow() ) oder Operator (oft als ^ oder ** ) verfügbar.

Bei Verwendung großer Zahlenwerte (= langer Iterations-Reihen) kann man an die Grenze des Variablen-Typs kommen, das ist für den Typ Double ca 1.8E+308

Das Beispiel zeigt, wie man die Potenz-Funktion selbst programmieren kann.

Anwendung:
x_hoch_y = my_pow(x,y)
Basic (VBA) Hilfs-Funktion my_pow()
Private Function my_pow( _
ByVal number As Double, _
ByVal exponent As Integer) _
As Double
Dim i As Integer
Dim p As Double
p = 1
For i = 1 To exponent
p = p * number
Next
my_pow = p
End Function
Javascript Hilfs-Funktion my_pow()
function my_pow(b,ie) {
var p=1;
for(var i=1;i<=ie;i++) {p*=b;}
return p;
}
Anwendung in Javascript:
x_hoch_y = my_pow(x,y);
C/C++ Hilfs-Funktion my_pow()
Deklaration:
double my_pow(double,int);
Funktion:
double my_pow(double b,int ie) {
int i;
double p=1;
for(i=0;i<ie;i++) {p*=b;}
return p;
}
Anwendung in C/C++:
x_hoch_y = my_pow(x,y);

Fakultät-Funktion

Das Beispiel zeigt, wie man die → Fakultät-Funktion (engl. factorial) ausschließlich unter Verwendung der 4 Grundrechnungs-Arten programmieren kann:
x_fakt = 1 * 2 * 3 * ... * x

Die Fakultät-Funktion wächst besonders rasch: Sie ist nur verwendbar bis maximal
170! = 7.26E+306
Basic (VBA) Hilfs-Funktion my_fakt()
Private Function my_fakt( _
ByVal number As Integer) _
As Double
Dim i As Integer
Dim f As Double
f = 1
For i = 1 To number
f = f * i
Next
my_fakt = f
End Function

Anwendung:
x_fakultaet = my_fakt(x)
Javascript Hilfs-Funktion my_fakt()
function my_fakt(n) {
var f=1;
for(var i=1;i<=n;i++) {f*=i;}
return f;
}
Anwendung in Javascript:
n_fakultaet = my_fakt(n);
C / C++ Hilfs-Funktion my_fakt()
Deklaration:
double my_fakt(int);
Funktion:
double my_fakt(int n) {
int i;
double f=1;
for(i=1;i<=n;i++) {f*=(double)i;}
return f;
}
Anwendung in C / C++:
n_fakultaet = my_fakt(n);

Quadratwurzel-Funktion

Diese Funktion wird von den meisten Programmiersprachen als sqr() oder sqrt() angeboten.

Die Berechnung mit Hilfe einer Reihen-Entwicklung wird auf der Seite → Quadratwurzel demonstriert.