3.6    Datentypen für Fließkommazahlen

Fließkommaliterale sind Werte mit einer Nachkommastelle und enthalten ein Dezimaltrennzeichen in Form eines Punktes (beispielsweise 3.1415, .25, 33. usw.). Auch eine wissenschaftliche Schreibweise des Exponenten als Zehnerpotenz ist möglich (22.44e–3 entspricht z. B. 0.02244). Im Standard finden Sie die folgenden Fließkommatypen:

Datentyp

Wertebereich

Formatzeichen

Genauigkeit

float

1.2E–38
3.4E+38

%f

einfach

double

2.3E–308
1.7E+308

%f
(%lf für scanf)

doppelt

long double

3.4E–4932
1.1E+4932

%Lf

zusätzlich

Tabelle 3.3    Datentypen für Fließkommazahlen

Beachten Sie, dass die Genauigkeit und die Wertebereiche dieser Typen komplett implementierungsabhängig sind. Es ist lediglich gewährleistet, dass bei float, double und long double (hier von links nach rechts) jeder Typ den Wert des vorherigen aufnehmen kann. Auf den meisten Architekturen entsprechen float und double den IEEE-Datentypen. Die Norm IEEE 754 definiert dabei die Darstellungen für binäre Gleitkommazahlen im Computer.

Bevorzugter Fließkommatyp

In der Praxis empfiehlt es sich, immer den Fließkommatyp double zu verwenden, weil der Compiler den Typ float intern häufig ohnehin in den Typ double umwandelt.

Im Gegensatz zu den Ganzzahlen gibt es bei den Fließkommazahlen keine Unterschiede zwischen vorzeichenbehafteten und vorzeichenlosen Zahlen. In C++, einer Variante von Standard-C, sind alle Fließkommazahlen vorzeichenbehaftet.

Beachten Sie außerdem, dass die Trennzeichen bei den Fließkommazahlen in US-amerikanischer Schreibweise angegeben werden. Anstatt eines Kommas zwischen den Zahlen müssen Sie einen Punkt setzen (man spricht im Englischen von floating point variables):

double pi = 3,14159265;   // FALSCH
double pi = 3.14159265; // RICHTIG

Wenn einer der Werte vor oder nach dem Dezimalpunkt 0 ist, beispielsweise 0.5 oder 1.0, können Sie die Ziffer 0 auch weglassen. Der Compiler ergänzt die 0 automatisch.

double c = .5;  // entspricht 0.5
double d = 5.; // entspricht 5.0
»float_t« und »double_t«

Erwähnt werden sollten an dieser Stelle noch die Gleitkommatypen float_t und double_t aus der Header-Datei math.h, die seit C99 vorhanden sind, mit denen bei arithmetischen Operationen intern gerechnet wird und durch die die notwendigen Konvertierungen entfallen. Welcher Typ dabei verwendet wird, hängt vom Wert des Makros FLT_EVAL_METHOD ab.

3.6.1    Suffixe für Fließkommazahlen

Wie den Ganzzahlen können Sie den Fließkommazahlen ebenfalls ein Suffix hinzufügen. Mit dem Suffix f oder F kennzeichnen Sie eine Fließkommazahl mit einer einfachen Genauigkeit (float). Das Suffix l oder L hingegen deutet auf eine Fließkommazahl mit erhöhter Genauigkeit hin (long double). Ohne eine Angabe bei Fließkommazahlen wird der Typ double verwendet. Die Verwendung des Exponenten, mit dem die Größe der Zahl als Zehnerpotenz angegeben wird, kann mit e oder E (beide Buchstaben haben dieselbe Bedeutung), gefolgt von einem optionalen + oder und einer Ziffernsequenz, notiert werden (22.45e0 etwa entspricht 22.45, 22.45e1 entspricht 224.5, und 22.45e–3 ist 0.02245). Im Folgenden finden Sie hierzu einige Beispiele:

float fVal = 3.33f;
long double ldVal = 32.32L;
double eVal1 = 4.3e10;
double eVal2 = 3.4e-5;
long double eVal3 = 8.4e123L;

3.6.2    Komplexe Gleitkommatypen

Seit dem C99-Standard werden auch komplexe Gleitkommatypen in der Header-Datei complex.h implementiert. Eine komplexe Zahl wird hierbei als Paar aus Real- und Imaginärteil dargestellt, die auch mit den Funktionen creal() und cimag() ausgegeben werden können. Beide Teile der komplexen Zahl bestehen entweder aus den Typen float, double oder long double. Daher gibt es wie bei den reellen Gleitpunktzahlen die folgenden drei komplexen Gleitkommatypen:

float _Complex
double _Complex
long double _Complex

Um die umständliche Schreibweise mit dem Unterstrich _Complex zu vermeiden, ist in der Header-Datei complex.h das Makro complex definiert. Anstelle des Schlüsselwortes _Complex können Sie auch complex verwenden:

float complex        // gleich wie float _Complex
double complex // gleich wie double _Complex
long double complex // gleich wie long double _Complex

Da komplexe Zahlen einen Real- und einen Imaginärteil haben, beträgt die Größe des Datentyps in der Regel das Doppelte der Größe der grundlegenden Datentypen. Ein float _Complex benötigt somit 8 Bytes, weil im Grunde genommen zwei float-Elemente benötigt werden. Folgendes Listing soll das verdeutlichen:

00  // Kapitel3/komplexe_zahlen.c
01 #include <stdio.h>
02 #include <complex.h>

03 int main(void) {
04 float complex fc = 2.0 + 3.0*I;
05 // 4 Bytes
06 printf("sizeof(float) : %zu\n", sizeof(float));
07 // 8 Bytes (realer und imaginärer Teil)
08 printf("sizeof(float complex) : %zu\n",
sizeof(float complex));
09 // Ausgabe von Real- und Imaginärteil
10 printf("%f + %f\n", creal(fc), cimag(fc));
11 return 0;
12 }

Listing 3.1    komplexe_zahlen.c zeigt den Umgang mit komplexen Zahlen

Des Weiteren ist in der Header-Datei das Makro I definiert, das die imaginäre Einheit mit dem Typ const float complex darstellt. Vielleicht hier eine kurze Hintergrundinformation zu komplexen Gleitpunktzahlen: Eine komplexe Zahl zVal wird beispielsweise folgendermaßen in einem kartesischen Koordinatensystem dargestellt:

zVal = xVal + yVal * I

xVal und yVal sind dabei reelle Zahlen, und I ist der imaginäre Teil. Die Zahl xVal wird hier als realer Teil betrachtet, und yVal ist der imaginäre Teil von zVal.

Ebenfalls in C99 eingeführt wurden Gleitkomma-Datentypen für rein imaginäre Zahlen mit float _Imaginary, double _Imaginary und long double _Imaginary.

Wenn Sie jetzt nicht das nötige mathematische Hintergrundwissen über komplexe Zahlen haben, macht dies an dieser Stelle nichts. Aber ohne die Erwähnung von complex.h wäre dieses Buch schlicht unvollständig.