Zahlenformatierung in C++
Diese Lektion behandelt einige Aspekte der Formatierung von Wertdarstellungen in C++.
Strommanipulatoren
Der Operator "<<" akzeptiert als zweiten Operanden auch einen Strommanipulator. Die Wirkung dieser Operation ist die Manipulation des linken Operanden, also des Ausgabestroms. Ein Ausgabestrom kennt verschiedene Betriebsarten, die bestimmen, wie Werte dargestellt werden.
Feldbreite
::std::setw
Eine Ausgabe kann auf eine bestimmten Mindestbreite aufgefüllt werden, die durch dem Manipulator "::std::setw" eingestellt werden kann. Normalerweise wird durch das Voranstellen von Leerzeichen aufgefüllt. In der Synopse "::std::setw" steht der Text "T" für einen nicht näher bestimmten Typ.
::std::setw [Synopse]
#include <iomanip>
T ::std::setw( int n );
Das folgende Beispielprogramm zeigt die Verwendung von "::std::setw". Dabei wird auch gezeigt, wie der Manipulator "::std::right" und der Manipulator "::std::left" verwendet wird, um die Ausrichtung der Ausgabe in dem Feld festzulegen und wie mit dem Manipulator "::std::setfill" ein Füllzeichen eingestellt werden kann.
width.cpp
#include <iostream> // ::std::cout
#include <ostream> // ::std::ostream (<<)
#include <iomanip> // ::std::setw, ::std::setfill
#include <ios> // ::std::left, ::std::right
int main()
{ ::std::cout <<
::std::setw( 1 ) << 247 << "|\n" <<
::std::setw( 10 ) << 248 << "|\n" <<
::std::setw( 10 )<< ::std::right << 2490 << "|\n" <<
250 << "|\n" <<
::std::setw( 10 )<< ::std::left << 251 << "|\n" <<
::std::setw( 10 )<< ::std::right <<
::std::setfill( '-' )<< 252 << "|\n" <<
::std::setw( 10 )<< ::std::left <<
::std::setfill( '-' )<< 253 << "|\n" <<
254 << "|\n"; }::std::cout
247|
248|
2490|
250|
251 |
-------252|
253-------|
254|
Die Angabe einer Feldbreite gilt nur für die nächste folgende Ausgabe, daher werden die Zahl "250" und die Zahl "254" nicht mehr in ein Feld der zuvor angegebenen Breite geschrieben. Alle anderen Manipulatoren verändern den Strom hingegen dauerhaft.
Festkomma- und Zehnerpotenzschreibweise
Bei der Darstellung von Gleitkommazahlen sind grundsätzlich zwei Schreibweisen möglich: Die Festkommaschreibweise und die Zehnerpotenzschreibweise: Das Festkommabit und das Zehnerpotenzbit eines Stroms speichert, ob die Festkommaschreibweise oder die Zehnerpotenzschreibweise bei Ausgaben in den Strom verwendet werden soll.
::std::fixed
Der Manipulator "::std::fixed" setzt das Festkommabit und löscht das Zehnerpotenzbit des Stromes. Dadurch wird die Festkommaschreibweise für die Ausgabe eingestellt.
Die Festkommaschreibweise verwendet eine einfache Schreibweise mit einem eventuellen Vorzeichen, Vorkommastellen, einem Dezimaltrennzeichen und so vielen Nachkommastellen wie die festgelegte Genauigkeit angibt, die normalerweise 6 beträgt; die auszugebende Zahl wird dazu nötigenfalls gerundet.
fixed.cpp
#include <iostream> // ::std::cout
#include <ostream> // ::std::ostream (<<)
#include <ios> // ::std::fixed
int main()
{ ::std::cout << 1234567890.1234567890 << "|\n" <<
::std::fixed << 2234567890.1234567890 << "|\n" <<
3.1 << "|\n" <<
4. << "|\n"; }::std::cout
1.23457e+009|
2234567890.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. Das wird durch den Manipulator "::std::fixed" bewirkt, da dieser ja eine feste Zahl von Nachkommastellen festlegt.
fields.cpp
#include <iostream> // ::std::cout
#include <ostream> // ::std::ostream (<<)
#include <iomanip> // ::std::setw
#include <ios> // ::std::fixed
int main()
{ ::std::cout << ::std::right
<< ::std::setw( 12 )<< 12.0000 << "|\n"
<< ::std::setw( 12 )<< 221.1000 << "|\n"
<< ::std::setw( 12 )<< 3211.1200 << "|\n\n"
<< ::std::fixed
<< ::std::setw( 12 )<< 42.0000 << "|\n"
<< ::std::setw( 12 )<< 521.1000 << "|\n"
<< ::std::setw( 12 )<< 6211.1200 << "|\n"; }::std::cout
12|
221.1|
3211.12|
42.000000|
521.100000|
6211.120000|
::std::scientific
Der Manipulator "::std::scientific" setzt das Zehnerpotenzbit und löscht das Festkommabit des Stromes. Dadurch wird die Zehnerpotenzschreibweise für die Ausgabe eingestellt.
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.
Der Manipulator "::std::uppercase" erlaubt es, Großschreibung für die Buchstaben der Ausgabe zu verlangen und kann durch den Manipulator "::std::nouppercase" wieder aufgehoben werden.
scientific.cpp
#include <iostream> // ::std::cout
#include <ostream> // ::std::ostream (<<)
#include <ios> // ::std::scientific,
// ::std::uppercase, ::std::nouppercase
int main()
{ ::std::cout << 1.23 << "|\n" <<
::std::scientific << 2.23 << "|\n" <<
3.1 << "|\n" <<
4. << "|\n" <<
::std::uppercase << 5.23 << "|\n" <<
::std::nouppercase << 6.23 << "|\n"; }::std::cout
1.23|
2.230000e+000|
3.100000e+000|
4.000000e+000|
5.230000E+000|
6.230000e+000|
Kombinationen
Das Festkommabit und das Zehnerpotenzbit schließen sich nicht gegenseitig aus. Es ist möglich, daß beide oder keines von beiden gesetzt sind. In dem von C++ vorgegebenen Anfangszustand ist keines von beiden gesetzt. Durch den Manipulator "::std::resetiosflags( ::std::ios::scientific )" kann ein einmal gesetztes Zehnerpotenzbit wieder zurückgesetzt werden. Beide Bits zu setzen ist zwar mit den bisher vorgestellten Manipulatoren nicht möglich, aber falls es auf anderen Weg geschehen ist, dann verhält sich der Ausgabestrom so als sei keines der beiden Bits gesetzt.
resetiosflags.cpp
#include <iostream> // ::std::cout
#include <ostream> // ::std::ostream (<<)
#include <ios> // ::std::scientific, ::std::ios::scientific
#include <iomanip> // ::std::resetiosflags
int main()
{ ::std::cout << 1.23 << "|\n" <<
::std::scientific << 2.23 << "|\n" <<
::std::resetiosflags( ::std::ios::scientific )<< 3.23 << "|\n"; }::std::cout
1.23|
2.230000e+000|
3.23|
Ist keines der beiden Bits gesetzt, wird die Zehnerpotenzschreibweise zur Ausgabe 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.cpp
#include <iostream> // ::std::cout
#include <ostream> // ::std::ostream (<<)
int main()
{ ::std::cout <<
5 << "|\n" <<
1.23 << "|\n" <<
0.0004 << "|\n" <<
0.00005 << "|\n" <<
500000. << "|\n" <<
6000000. << "|\n"; }::std::cout
5|
1.23|
0.0004|
5e-005|
500000|
6e+006|
Genauigkeit
Der Strommanipulator "::std::setprecision" erlaubt es, die „Genauigkeit“ eines Ausgabestroms einzustellen, die dann verschiedene Zahlendarstellungen beeinflußt. Der Vorgabewert für die Genauigkeit ist 6.
::std::setprecision [Synopse]
#include <iomanip>
T setprecision( int n );
Falls keine Festkomma- oder Zehnerpotenzschreibweise verlangt wird, dann bestimmt die Genauigkeit die Zahl der gesamten Stellen, sonst die Zahl der Nachkommastellen der Festpunktzahl oder der Zahl vor dem E bei der Zehnerpotenzschreibweise.
precision.cpp
#include <iostream> // ::std::cout
#include <ostream> // ::std::ostream (<<)
#include <ios> // ::std::scientific, ::std::ios::scientific
#include <iomanip> // ::std::resetiosflags, ::std::setprecision
int main()
{ ::std::cout << 12.3456789 << "|\n" <<
::std::scientific << 22.3456789 << "|\n" <<
::std::resetiosflags( ::std::ios::scientific )<< 32.3456789 << "|\n" <<
::std::setprecision( 12 ) << 42.3456789 << "|\n" <<
::std::scientific << 52.3456789 << "|\n" <<
::std::resetiosflags( ::std::ios::scientific )<< 62.3456789 << "|\n"; }::std::cout
12.3457|
2.234568e+001|
32.3457|
42.3456789|
5.234567890000e+001|
62.3456789|
Alternative Darstellungsform
Der Strommanipulator "::std::showpoint" stellt einen Ausgabestrom auf eine „alternative“ Darstellungsform um.
::std::showpoint [Synopse]
#include <ios>
ios_base & ::std::showpoint( ios_base & str );
Endnullen werden in der vorgegebenen Standardschreibweise (in der das Festkommabit und das Zehnerpotenzbit beide nicht gesetzt sind) nach dem Dezimaltrennzeichen nur geschrieben, wenn die alternative Darstellungsart "showpoint" aktiviert wurde. Insofern ist der Name "showpoint" etwas irreführend, da die Darstellungsart nicht immer bestimmt, ob ein Punkt angezeigt wird, sondern auch, ob Endnullen nach dem Dezimaltrennzeichen ausgegeben werden. Falls die Genauigkeit Null ist und die alternative Darstellungsart "showpoint" nicht aktiv ist, wird kein Dezimaltrennzeichen geschrieben (sowohl bei Festpunktschreibweise als auch bei Zehnerpotenzschreibweise).
::std::noshowpoint [Synopse]
#include <ios>
ios_base & ::std::noshowpoint( ios_base & str );
Mit "::std::noshowpoint" kann die alternative Darstellungsart "showpoint" wieder deaktiviert werden.
Das folgende Programmbeispiel zeigt einige Aspekte der Wirkung der verwendeten Betriebsart.
showpoint.cpp
#include <iostream> // ::std::cout
#include <ostream> // ::std::ostream (<<)
#include <ios> // ::std::ios::scientific, ::std::showpoint
// ::std::scientific, ::std::noshowpoint
#include <iomanip> // ::std::resetiosflags, ::std::setprecision
int main()
{ ::std::cout <<
::std::setprecision( 12 ) << 12.3456789 << "|\n" <<
::std::scientific << 22.3456789 << "|\n" <<
::std::resetiosflags( ::std::ios::scientific )<<
::std::showpoint << 32.3456789 << "|\n" <<
::std::scientific << 42.3456789 << "|\n" <<
::std::resetiosflags( ::std::ios::scientific )<<
::std::noshowpoint << ::std::setprecision( 0 )<< 52. << "|\n" <<
::std::showpoint << 62. << "|\n" <<
::std::fixed << 72. << "|\n" <<
::std::noshowpoint <<::std::setprecision( 12 )<< 82.3456789 << "|\n"; }::std::cout
12.3456789|
2.234567890000e+001|
32.3456789000|
4.234567890000e+001|
52|
62.0000|
72.|
82.345678900000|
Die Ausgabe des Programms "showpoint.cpp" zeigt in den ersten vier Zeilen, wie die Festlegung der alternativen Darstellungsart bewirkt, ob Endnullen nach dem Dezimaltrennzeichen ausgegeben werden.
In der vorvorletzten Zeile würde man eher "62." erwarten, da die eingestellte Genauigkeit gleich 0 ist. Aus dem gleichen Grund sollte für den double-Wert "52." und den double-Wert "62." die Zehnerpotenzdarstellung verwendet werden (der Exponent wäre größergleich der Genauigkeit). Doch C++ verwendet diese Genauigkeit hier nur dann zur Formatierung, wenn das Festkommabit gesetzt ist oder die Genauigkeit größer als 0 ist. Daher kann die Ausgabe "72." erst nach Setzen des Festkommabits erhalten werden und der double-Wert "52." und der double-Wert "62." werden beide mit der Festkommaschreibweise geschrieben.
Man beachte auch, daß die Genauigkeit von 12 sich nach dem Manipulator "::std::showpoint" ohne den Manipulator "::std::fixed" auf die Zahl der gesamten Stellen bezieht, so daß "32.3456789000" insgesamt 12 Stellen und 10 Nachkommastellen hat. Nach dem Manipulator "::std::fixed" bezieht sich die Genauigkeit von 12 auf die Nachkommastellen, so daß "82.345678900000" 12 Nachkommastellen hat. Außerdem werden hier wegen des Manipulators "::std::fixed" Endnullen geschrieben, obwohl der Manipulator "::std::noshowpoint" voranging.