4.8    Mathematische Funktionen in C

Die Standardbibliothek beinhaltet eine umfangreiche Sammlung von mathematischen Funktionen, zu denen Sie hier einen kleinen Überblick erhalten. Die meisten dieser Funktionen sind in der Header-Datei math.h deklariert. Sie sind zu einem großen Teil für Gleitpunktzahlen oder für komplexe Gleitpunkttypen (aus der Header-Datei complex.h) geeignet. Zwar bietet die Standardbibliothek auch einige Funktionen für ganzzahlige Typen, diese sind aber vorwiegend in der Header-Datei stdlib.h bzw. für den Typ intmax_t in inttypes.h deklariert. Des Weiteren sind in der Header-Datei tgmath.h typengenerische Makros definiert, mit denen es möglich ist, mathematische Funktionen mit einem einheitlichen Namen aufzurufen, und zwar unabhängig vom Typ des Arguments.

Verwendung der Mathe-Bibliothek unter Linux

Damit Sie auch bei Linux-Programmen die mathematische Standardbibliothek verwenden können, müssen Sie zusätzlich das Compiler-Flag -lm (beispielsweise gcc -o programm programm.c -lm) angeben, um die Mathe-Bibliothek per Hand hinzuzulinken.

Zu jeder mathematischen Funktion gibt es eine Version mit float bzw. float _Complex, double bzw. double _Complex und eine Version für long double bzw. long double _Complex. Die Versionen von float bzw. float _Complex haben das Suffix f am Ende des Funktionsnamens, die Versionen für long double bzw. long double _Complex das Suffix l. Für die Version von double bzw. double _Complex wird kein Suffix benötigt. Sofern Sie allerdings die Header-Datei tgmath.h verwenden, können Sie das Suffix ganz außer Acht lassen.

complex.h und der Fehler no such file or directory

complex.h wurde erst mit dem C99-Standard eingeführt. Der Compiler unterstützt die komplexen Standardfunktionen also nur, wenn er C99-konform ist. Ansonsten erhalten Sie die Fehlermeldung, dass die entsprechende Include-Datei nicht existiert.

Wenn Sie beispielsweise die Funktion zum Ziehen der Quadratwurzel für reelle double-Zahlen verwenden wollen, also

double sqrt(double zahl);

schreiben, existieren für die Funktion noch die folgenden float- und die long double-Versionen:

float sqrtf(float zahl);
long double sqrtl(long double zahl);

Gleiches gilt auch für die aufgelistete komplexe Gleitpunkttypversion. Diese beginnt zusätzlich mit dem Präfix c:

double complex csqrt(double complex z);

Auch von dieser Version gibt es zwei weitere Versionen:

float complex csqrtf(float complex z);
long double complex csqrtl(long double complex z);

Ein einfaches Anwendungsbeispiel demonstriert die Verwendung zum Ziehen der Quadratwurzel mit sqrt() aus math.h. Hierbei soll jeweils einmal der Fließkommatyp float, double und long double verwendet werden.

00  // Kapitel4/mathe_beispiel_1.c
01 #include <stdio.h>
02 #include <stdlib.h>
03 #include <math.h>
04 #include <complex.h> // C99

05 int main(void) {
06 long double ldval=8.8;
07 double dval=5.5;
08 float fval=3.3;

09 // Quadratwurzel mit reellen Zahlen
10 printf("Quadratwurzel-Berechnungen:\n");
11 printf("(long double) sqrtl(%Lf) = %Lf\n",ldval, sqrtl(ldval));
12 printf("(double) sqrt(%lf) = %lf\n",dval,sqrt(dval));
13 printf("(float) sqrtf(%f) = %f\n",fval,sqrtf(fval));
14 // Berechnung mit komplexen Zahlen
15 double pi = 4 * atan(1.0);
16 double complex c = cexp(I * pi);
17 printf("%lf + %lf * i\n", creal(c), cimag(c));
18 return 0;
19 }

Listing 4.5    mathe_beispiel_1.c zeigt Berechnungen mit reellen und komplexen Zahlen.

In den Zeilen (11) bis (13) werden jeweils Quadratwurzeln von long double, double und einer float-Zahl mit der entsprechenden Version des Fließkommatyps gezogen. In den Zeilen (15) bis (17) wird die Verwendung von Standardfunktionen für komplexe Zahlen (seit C99 dabei) demonstriert. Achten Sie außerdem bei der formatierten Ausgabe auf die richtige Formatangabe (%f, %lf und %Lf) des entsprechenden Gleitpunkttyps.

Typengenerische Makros (tgmath.h)

tgmath.h wurde mit dem C99-Standard eingeführt. In tgmath.h sind die Header-Dateien math.h und complex.h inkludiert und die sogenannten typengenerischen Makros definiert. Der Vorteil dieser Makros liegt darin, dass Sie diese unabhängig vom Typ des Arguments die mathematischen Funktionen mit demselben Namen aufrufen können. Das bedeutet, Sie können außer Acht lassen, welche mathematischen Funktionen Sie für die Typen float, double, long double, float complex, double complex und long double complex aufrufen.

Wollen Sie beispielsweise eine Funktion zum Ziehen der Quadratwurzel verwenden, müssen Sie abhängig vom Datentyp zwischen sechs verschiedenen Varianten mit sqrtf(), sqrt(), sqrtl(), csqrtf(), csqrt() und csqrtl() unterscheiden.

Mit den typengenerischen Makros in tgmath.h brauchen Sie sich darum keine Gedanken mehr zu machen. Hier müssen Sie lediglich die Funktionen der double- bzw. double complex-Variante kennen, und ein Aufruf von sqrt() führt automatisch die entsprechende Erweiterung aus. Rufen Sie beispielsweise sqrt() mit einem float complex-Argument auf, wird automatisch die Erweiterung csqrtf() ausgeführt.

Hierzu folgt ein Beispiel, das diese typengenerischen Makros demonstrieren soll. Für alle reellen und komplexen Gleitpunkttypen wird immer nur die Funktion sqrt() zum Ziehen der Quadratwurzel aufgerufen. Das wäre ohne die typengenerischen Makros nicht denkbar, und bei Compilern, die den C99-Standard nicht unterstützen, ist es auch nicht möglich. Es folgt nun ein Beispiel, das das eben gesagte demonstriert:

00  // Kapitel4/mathe_beispiel_2.c
01 #include <stdio.h>
02 #include <stdlib.h>
03 #include <tgmath.h>

04 int main(void) {
05 long double ldval=8.8;
06 double dval=5.5;
07 float fval=3.3;
08 double complex dcval= 1.0 + 2.0*I;

09 // Quadratwurzel mit reellen Zahlen
10 printf("Quadratwurzel-Berechnungen:\n");
11 printf("(long double) sqrt(%Lf) = %Lf\n",ldval, sqrt(ldval));
12 printf("(double) sqrt(%lf) = %lf\n",dval, sqrt(dval));
13 printf("(float) sqrt(%f) = %f\n",fval, sqrt(fval));
14 double complex dcval_G = sqrt(dcval);
15 printf("(double complex) sqrt(4.0 + 2.0*I)"
" = %lf + %lfi\n", creal(dcval_G), cimag(dcval_G));
16 return 0;
17 }

Listing 4.6    mathe_beispiel_2.c zeigt, wie Sie die typengenerischen Makros in tgmath.h verwenden.

Hier finden Sie die Berechnungen mit der Funktion sqrt(), ohne auf die Fließkommatypen zu achten, in den Zeilen (11) bis (14).

Weitere mathematische Angebote der Standardbibliothek

Natürlich bietet die Standardbibliothek noch weitere nützliche Features rund um die mathematischen Funktionen. Dieser Bereich wurde besonders seit dem C99-Standard stark erweitert. Zu erwähnen wären hier Konstanten und Makros, um Fließkommawerte zu klassifizieren, sowie Makros für den Vergleich von reellen Zahlen und den Zugriff auf eine Fließkomma-Umgebung in fenv.h.