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, dann 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 Gleitpunkttyp-Version. Diese beginnt zusätzlich mit dem Präfix c:

double complex csqrt(double complex z); 

Auch von dieser Version gibt es zwei weitere Varianten:

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 besteht darin, dass Sie 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 eigentlich abhängig vom Datentyp zwischen sechs verschiedenen Varianten unterscheiden: sqrtf(), sqrt(), sqrtl(), csqrtf(), csqrt() und csqrtl().

Mit den typengenerischen Makros in tgmath.h brauchen Sie sich darüber 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.

Das Beispiel in Listing 4.6 demonstriert diese typengenerischen Makros. 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. So sieht der Code aus:

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.