Zahlenformatierung in C
Schauplatz
Die Formatierung eines Ausgabestroms in C hängt vom eingestellten Schauplatz (locale , [lo 'kæl]) ab. Mit der Standardfunktion "setlocale" kann ein Schauplatz eingestellt werden. Das erste Argument sollte "LC_ALL" sein, damit sich der neue Schauplatz auf alle Aspekte auswirkt. Das zweite Argument ist der Name des neuen Schauplatzes. Als Name des Schauplatzes ist der leere Text "" möglich, um den Schauplatz der Umgebung zu bezeichnen oder der Text "C" für den klassischen Schauplatz der Programmiersprache C.
setlocale [Synopse]
#include <locale.h>
char * setlocale( int category, const char *locale );
Das Beispielprogramm "locale.c" zeigt, wie der Schauplatzes "" für die aktuelle Umgebung mit der Funktion "setlocale" eingestellt wird. Das Ausgabebeispiel läßt erkennen, daß dann statt eines Dezimalpunktes das in diesem Schauplatz dafür festgelegtes Dezimalkomma in der Ausgabe verwendet wird. Das Dezimalkomma und die anderen Festlegungen für die deutsche Sprache werden allerdings dabei nur dann verwendet, wenn das auch so in dem verwendeten Schauplatz (der Umgebung, dem verwendeten Betriebssystem) eingestellt wurde. Nach dem Einstellen des Standardwertes "C" wird dann wieder ein Dezimalpunkt verwendet.
locale.c
#include <stdio.h>
#include <locale.h>
int main( void )
{ printf( "%g|\n", 1.23 );
setlocale( LC_ALL, "" );
printf( "%g|\n", 2.23 );
setlocale( LC_ALL, "C" );
printf( "%g|\n", 3.23 ); }stdout
1.23|
2,23|
3.23|
Wenn in einem C-Programm Text einer formalen Sprache, die einen Dezimalpunkt erwartet, ausgegeben werden soll, so ist es in der Regel angebracht, wenn der Programmteil, in dem dies geschieht, den C-Schauplatz vor der Formatierung immer ausdrücklich einstellt, weil ein Programmteil in der Regel nicht sicher weiß, ob irgendwelche anderen Programmteile den Schauplatz nicht verstellt haben könnte.
Feldgröße
Für die Ausgabe einer Zahl kann eine Feldgröße (Mindestbreite) festgelegt werden. Falls die Zahlendarstellung weniger Zeichen als die Feldgröße hat, werden vor der Zahl Leerzeichen ausgegeben, um insgesamt so viele Zeichen auszugeben, wie durch die Feldgröße festgelegt sind.
minwidth.c
#include <stdio.h>
int main( void )
{ printf( "01234567\n" );
printf( "%8g|\n", 12.34 );
printf( "%8g|\n", 1234.5678 );
printf( "%8g|\n", 0.0478 );
printf( "%8g|\n", 422121.0 );
printf( "%8g|\n", 422121234.345345 ); }stdout
01234567
12.34|
1234.57|
0.0478|
422121|
4.22121e+008|
Wenn die Feldgröße ein Sternchen "*" ist, dann wird dafür ein Argumentwert verwendet. Im Programmbeispiel "parwidth.c" ist die Feldgröße für das erste Sternchen also acht und für das zweite sieben.
parwidth.c
#include <stdio.h>
int main( void )
{ printf( "01234567\n" );
printf( "%*g|\n", 8, 12.34 );
printf( "%*g|\n", 7, 12.34 ); }stdout
01234567
12.34|
12.34|
Kennzeichen
Nach dem Prozentzeichen "%" und vor einer eventuell angegebenen Feldbreite können noch verschiedene Kennzeichen angegeben werden.
Durch ein Minuszeichen "-" nach dem Prozentzeichen "%" wird Auffüllen durch Leerzeichen nach der Zahl verlangt.
leftalign.c
#include <stdio.h>
int main( void )
{ printf( "01234567|\n" );
printf( "%8g|\n", 12.34 );
printf( "%-8g|\n", 12.34 ); }stdout
01234567|
12.34|
12.34 |
Ein Pluszeichen "+" verlangt Ausgabe des Vorzeichens, selbst wenn dies positiv ist und ein Leerzeichen " " bestimmt, daß ein positives Vorzeichen als Leerzeichen darzustellen ist.
sign.c
#include <stdio.h>
int main( void )
{ printf( "%g|\n", 2. );
printf( "%+g|\n", 2. );
printf( "% g|\n", 2. ); }stdout
2|
+2|
2|
Eine Null "0" verlangt das Auffüllen mit führende Nullen.
null.c
#include <stdio.h>
int main( void )
{ printf( "%3g|\n", 2. );
printf( "%03g|\n", 2. ); }stdout
2|
002|
Die bisher gezeigten Möglichkeiten können auch kombiniert werden und auch mit anderen numerischen Umwandlungsspezifizierer als dem Buchstaben "g" zusammen verwendet werden.
So können beispielsweise auch mehrere Kennzeichen angegeben werden. Wird das Kennzeichen "0" zusammen mit dem Kennzeichen "-" verwendet, so wird das Kennzeichen "0" allerdings ignoriert. Genauso wird das Leerzeichen " " als Kennzeichen ignoriert, wenn auch ein Pluszeichen "+" vorkommt. Die Reihenfolge der Kennzeichen ist egal.
combination.c
#include <stdio.h>
int main( void )
{ printf( "%+-09g|\n", 2. );
printf( "%0-+9g|\n", 2. ); }stdout
+2 |
+2 |
Schreibweisen
Bei der Darstellung von Gleitkommazahlen sind drei Schreibweisen möglich: Die gemischte Schreibweise, die Festkommaschreibweise und die Zehnerpotenzschreibweise.
Die Festkommaschreibweise
Der Umwandlungsspezifizierer "f" verlangt die Festkommaschreibweise zur Ausgabe einer Gleitkommazahl.
Die Festkommaschreibweise verwendet eine einfache Schreibweise mit einem eventuellen Vorzeichen, Vorkommastellen, einem Dezimaltrennzeichen und so vielen Nachkommastellen wie die festgelegte Genauigkeit angibt, die normalerweise sechs beträgt; die auszugebende Zahl wird dazu nötigenfalls gerunden.
In dem Programm "fixpoint.c" wird eine Zahl zum Vergleich mit dem Formatspezifizierer "g" für die gemischte Schreibweise ausgegeben.
fixpoint.c
#include <stdio.h>
int main( void )
{ printf( "%g|\n", 1234567890.1234567890 );
printf( "%f|\n", 1234567890.1234567890 );
printf( "%f|\n", 3.1 );
printf( "%f|\n", 4. ); }stdout
1.23457e+009|
1234567890.123457|
3.100000|
4.000000|
Um Zahlen in einem Feld einer bestimmten Breite untereinander rechts ausgerichtet auszugeben, sollten auch Endnullen nach dem Dezimaltrennzeichen ausgegeben werden, damit alle Zahlen gleich viele Nachkommastellen haben. Auch das wird durch die Formatierung mit dem Umwandlungsspezifizierer "f" bewirkt, da dieser ja eine feste Zahl von Nachkommastellen festlegt.
In dem Programm "fields.c" werden zum Vergleich einige Zahlen mit dem Formatspezifizierer "g" für die gemischte Schreibweise ausgegeben.
fields.c
#include <stdio.h>
int main( void )
{ printf( "%12g|\n", 12.0000 );
printf( "%12g|\n", 221.1000 );
printf( "%12g|\n\n", 3211.1200 );
printf( "%12f|\n", 42.0000 );
printf( "%12f|\n", 521.1000 );
printf( "%12f|\n", 6211.1200 ); }stdout
12|
221.1|
3211.12|
42.000000|
521.100000|
6211.120000|
Die Zehnerpotenzschreibweise
Die Zahlenformatierung mit dem Umwandlungsspezifizierer "e" verlangt die Zehnerpotenzschreibweise zur Ausgabe einer Gleitkommazahl.
Bei der Zehnerpotenzschreibweise wird eine Gleitkommazahl als Produkt aus einer Zahl und einer Zehnerpotenz geschrieben. Die Zahl besteht aus einer Ziffer vor dem Dezimaltrennzeichen und eventuell weiteren Ziffern danach (die Anzahl dieser Ziffern nach dem Dezimaltrennzeichen kann durch eine Einstellung der Genauigkeit festgelegt werden). Die Zehnerpotenz wird durch eine auf ein E folgenden Zahl bestimmt, die den Exponenten von 10 angibt. Diese Zahl hat immer mindestens zwei Ziffern und weitere Ziffern nur falls nötig. So bedeutet die Schreibweise "3.2E-02" beispielsweise den Wert des Produktes 3,2 mit zehn hoch minus 2 (0,01), also 0,032.
Je nachdem, ob ein großes oder kleines E als Umwandlungsspezifizierer verwendet wird, erscheint ein großes bzw. kleines E in der Ausgabe.
In dem Programm "scientific.c" wird eine Zahl zum Vergleich mit dem Formatspezifizierer "g" für die gemischte Schreibweise ausgegeben.
scientific.c
#include <stdio.h>
int main( void )
{ printf( "%g|\n", 1.23 );
printf( "%E|\n", 1.23 );
printf( "%E|\n", 3.1 );
printf( "%E|\n", 4. );
printf( "%e|\n", 5.23 ); }stdout
1.23|
1.230000E+000|
3.100000E+000|
4.000000E+000|
5.230000e+000|
Gemischte Schreibweise
Der Umwandlungsspezifizierer "g" verlangt eine gemischte Schreibweise zur Ausgabe einer Gleitkommazahl. Die Zehnerpotenzschreibweise wird zur Ausgabe dabei nur dann verwendet, wenn der sich für die Ausgabe ergebende Exponent von Zehn kleiner als −4 oder größergleich der Genauigkeit ist, die normalerweise 6 beträgt. Endnullen erscheinen nicht, und ein Dezimaltrennzeichen wird nur ausgegeben, wenn noch eine Stelle folgt.
mixed.c
#include <stdio.h>
int main( void )
{ printf( "%g|\n", 5. );
printf( "%g|\n", 1.23 );
printf( "%g|\n", 0.0004 );
printf( "%g|\n", 0.00005 );
printf( "%g|\n", 500000. );
printf( "%g|\n", 6000000. ); }stdout
5|
1.23|
0.0004|
5e-005|
500000|
6e+006|
Genauigkeit
Nach dem Prozentzeichen "%" ist die Angabe von Kennzeichen, einer Feldbreite und einer Genauigkeit (in dieser Reihenfolge) möglich. Der Genauigkeit geht ein Punkt "." voran.
Für die Zehnerpotenzschreibweise bestimmt die Genauigkeit die Zahl der Nachkommastellen. Wird gar keine Genauigkeit (und auch kein Punkt) angegeben, so ist sie sechs. Wird nur ein Punkt geschrieben, ohne daß danach eine Angabe der Genauigkeit folgt, so gilt die Genauigkeit als Null.
precision.c
#include <stdio.h>
int main( void )
{ printf( "%.0e|\n", 1000.123456789123456789 );
printf( "%.1e|\n", 2000.123456789123456789 );
printf( "%.2e|\n", 3000.123456789123456789 );
printf( "%.10e|\n", 4000.123456789123456789 );
printf( "%.30e|\n", 5000.123456789123456789 );
printf( "%e|\n", 6000.123456789123456789 );
printf( "%.e|\n", 7000.123456789123456789 ); }stdout
1e+003|
2.0e+003|
3.00e+003|
4.0001234568e+003|
5.000123456789123300000000000000e+003|
6.000123e+003|
7e+003|
Auch für die Festkommaschreibweise bestimmt die Genauigkeit die Zahl der Nachkommastellen.
fixedprecision.c
#include <stdio.h>
int main( void )
{ printf( "%.0f|\n", 1000.123456789123456789 );
printf( "%.1f|\n", 2000.123456789123456789 );
printf( "%.2f|\n", 3000.123456789123456789 );
printf( "%.10f|\n", 4000.123456789123456789 );
printf( "%.30f|\n", 5000.123456789123456789 );
printf( "%f|\n", 6000.123456789123456789 );
printf( "%.f|\n", 7000.123456789123456789 ); }stdout
1000|
2000.1|
3000.12|
4000.1234567891|
5000.123456789123300000000000000000|
6000.123457|
7000|
Für die gemischte Schreibweise bestimmt die Genauigkeit die maximale Anzahl signifikanter Stellen (also der Stellen vor und nach dem Komma), die aber mindestens eins ist (selbst wenn Null angegeben wird), weswegen die Ausgabe der Zahl "1.0" und der Zahl "1.1" in dem Programm "mixedprecision.c" sich nicht voneinander unterscheiden.
mixedprecision.c
#include <stdio.h>
int main( void )
{ printf( "%.0g|\n", 1.0 );
printf( "%.1g|\n", 1.1 );
printf( "%.2g|\n", 1.2 );
printf( "%.0g|\n", 1000.123456789123456789 );
printf( "%.1g|\n", 2000.123456789123456789 );
printf( "%.2g|\n", 3000.123456789123456789 );
printf( "%.10g|\n", 4000.123456789123456789 );
printf( "%.30g|\n", 5000.123456789123456789 );
printf( "%g|\n", 6000.123456789123456789 ); }stdout
1|
1|
1.2|
1e+003|
2e+003|
3e+003|
4000.123457|
5000.1234567891233|
6000.12|
Auch für die Genauigkeit kann ein Sternchen "*" angegeben werden, um einen entsprechenden Argumentwert zu verwenden.
astprecision.c
#include <stdio.h>
int main( void )
{ printf( "%.*g|\n", 10, 1000.123456789123456789 ); }stdout
1000.123457|
Alternative Darstellungsform
Durch Verwendung des Kennzeichens "#" kann eine „alternative“ Darstellungsform verlangt werden.
Endnullen werden bei Verwendung des Umwandlungsspezifizierers "g" nach dem Dezimaltrennzeichen nur geschrieben, wenn die alternative Darstellungsart "#" aktiviert wurde. Die alternative Darstellungsart verlangt auch die Ausgabe eines Dezimaltrennzeichens: Falls die Genauigkeit Null ist und die alternative Darstellungsart "#" nicht aktiv ist, wird kein Dezimaltrennzeichen geschrieben.
number.c
#include <stdio.h>
int main( void )
{ printf( "%.12g|\n", 12.3456789 );
printf( "%.12e|\n", 22.3456789 );
printf( "%#.12g|\n", 32.3456789 );
printf( "%#.12e|\n", 42.3456789 );
printf( "%.g|\n", 52. );
printf( "%#.g|\n", 62. );
printf( "%#.f|\n", 72. );
printf( "%.12f|\n", 82.3456789 ); }stdout
12.3456789|
2.234567890000e+001|
32.3456789000|
4.234567890000e+001|
5e+001|
6.e+001|
72.|
82.345678900000|
Die Ausgabe des Programms "number.c" zeigt in den ersten vier Zeilen, wie die Festlegung der alternativen Darstellungsart beeinflußt, ob Endnullen nach dem Dezimaltrennzeichen ausgegeben werden.
Bei der Ausgabe des double-Wertes "52." und des double-Wertes "62." wird die Zehnerpotenzschreibweise verwendet, wie immer beim Umwandlungsspezifizierer "g", wenn der Exponent größergleich der Genauigkeit ist.
Man beachte auch, daß die Genauigkeit von 12 sich bei Verwendung des Umwandlungsspezifizierers "g" auf die Zahl der gesamten Stellen bezieht, so daß "32.3456789000" insgesamt 12 Stellen und 10 Nachkommastellen hat. Bei Verwendung des Umwandlungsspezifizierers "f" bezieht sich die Genauigkeit von 12 auf die Nachkommastellen, so daß "82.345678900000" 12 Nachkommastellen hat. Außerdem werden hier wegen des Umwandlungsspezifizierers "f" Endnullen geschrieben, obwohl kein Kennzeichen "#" verwendet wurde.
Ganzzahlige Werte ausgeben
Der Umwandlungsspezifizierer "d" (decimal ) und der Umwandlungsspezifizierer "i" (decimal ) haben die gleiche Bedeutung: Sie verlangen die Ausgabe eines int-Wertes im Dezimalsystem. Eine eventuell angegebene Genauigkeit (Vorgabewert Eins) bestimmt die Mindestzahl der Stellen. Die Ausgabe des Wertes Null mit einer Genauigkeit von Null hat allerdings Null Zeichen, während die Ausgabe eines anderen Wertes mit einer Genauigkeit von Null soviel Zeichen hat, wie sie für die übliche Darstellung nötig sind.
printint.c
#include <stdio.h>
int main( void )
{ printf( "%d|\n", 12 );
printf( "%i|\n", 22 );
printf( "%+d|\n", 32 );
printf( "% d|\n", 42 );
printf( "%6d|\n", 52 );
printf( "%.6d|\n", 62 );
printf( "%6.6d|\n", 72 );
printf( "%.d|\n", 0 );
printf( "%.d|\n", 1 );
printf( "%d|\n", 0 ); }stdout
12|
22|
+32|
42|
52|
000062|
000072|
|
1|
0|
Umwandlungsspezifikationen
Die beschriebenen, mit einem "%" beginnenden und mit einem Umwandlungsspezifizierer (Buchstaben) endenden Texte, wie beispielsweise der der Text "%9d", heißen Umwandlungsspezifikationen. Ihre Syntax kann man folgendermaßen beschreiben (vereinfacht).
- 〈Umwandlungsspezifikation 〉 ::=
- '%' 〈Optionen 〉 〈Umwandlungsspezifizierer 〉.
- 〈Umwandlungsspezifizierer 〉 ::=
- 'e' | 'f' | 'g' | 'd' | 'i' | '%'.
- 〈Optionen 〉 ::=
- {〈Kennzeichen 〉} [〈Mindestbreite 〉] [〈Genauigkeit 〉]
- 〈Kennzeichen 〉 ::=
- '+' | '-' | ' ' | '0' | '#'.
- 〈Mindestbreite 〉 ::=
- 〈Ziffer 〉 {〈Ziffer 〉}.
- 〈Ziffer 〉 ::=
- '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'.
- 〈Genauigkeit 〉 ::=
- '.' {〈Ziffer 〉}.
Wenn der Umwandlungsspezifizierer das Prozentzeichen "%" ist, dann muß die gesamte Umwandlungsspezifikation "%%" lauten und für diese Umwandlungsspezifikation darf kein Argument angegeben sein. Sie bezeichnet ein einfaches Prozentzeichen "%".
percent.c
#include <stdio.h>
int main( void )
{ printf( "%%|\n" ); }stdout
%|