Wie Zahlen mit 2 Nachkommastellen ausgeben?
-
Kleines Problem, hoffe ich wenigstens ....
Ich habe diverse Daten, double oder auch float, die ich auf dem Bildschirm ausgeben moechte, und zwar mit jeweils zwei Nachkommastellen.
Bei
123.24
klappt das natuerlich wunderbar, aber was mache ich bei
123
, da kriege ich dann auch nur
123
auf den Schirm, haette da aber gerne
123.00
stehen ...
Wie ich die Ausgabe bis auf zwei Nachkommastellen runde und/oder abschneide, das ist mir eigentlich klar. Aber wie haenge ich da im Zweifel zwei Nachkommastellen dran. Sowas wie den Typ "decimal" bei MySQL gibt es in C++ nicht, oder ...?
Gruss
Guenther
-
-
Hab's jetzt inzwischen so geloest ...
cout << "EkNetto: " << fixed << setprecision(2) << EkNetto << endl;
Es funktioniert, aber ist das auch "sauberes" C++?
-
jepp sauber genug;)
-
langeweile schrieb:
Danke, mal wieder 'ne interessante Seite, die ich mir unbedingt merken werde ...
-
BorisDieKlinge schrieb:
jepp sauber genug;)
"Sauber genug" ...., heisst das, man koennte es noch eleganter loesen?
-
ne... mir fällt nichts besseres ein
ich würde sicher noch
printf("%2.2i", zahl);
verwenden;) Die alte C gewohneit
-
BorisDieKlinge schrieb:
ne... mir fällt nichts besseres ein
ich würde sicher noch
printf("%2.2i", zahl);
verwenden;) Die alte C gewohneit
Sorry, Anfaengerfrage: Eigentlich soll man(n) doch aber C und C++ nicht mischen, obwohl das anscheinend halbwegs problemlos funktioniert.
Habe ich das so richtig verstanden?
-
Ja, verwende in C++ besser die typsicheren IO-Streams (anstatt printf und Konsorten).
Und, dein C++ Code ist so völlig korrekt.
-
gboelter schrieb:
Sorry, Anfaengerfrage: Eigentlich soll man(n) doch aber C und C++ nicht mischen, obwohl das anscheinend halbwegs problemlos funktioniert.
Habe ich das so richtig verstanden?
Das ist IMO eher eine Stilfrage.
Bis auf wenige Funktionen/Konstrukte die in C++ wirklich problematisch werden können (z.B. setjmp) funktioniert eigentlich alles tadellos wenn man C und C++ mischt.
Viele Leute verteufeln halt generell die Verwendung von C Funktionen/Konstrukten/... in C++ Code -- ich persönlich sehe das aber nicht SO eng.
-
hustbaer schrieb:
Bis auf wenige Funktionen/Konstrukte die in C++ wirklich problematisch werden können (z.B. setjmp) funktioniert eigentlich alles tadellos wenn man C und C++ mischt.
Etliche C Funktionen sind etwas (naja) unsicher, weil man sich "damals" noch nicht so viele Gedanken gemacht hatte (z.B. können String-Funktionen nicht überprüfen, wieviel Platz sie tatsächlich haben oder printf() nicht sicherstellen, daß die Formatkennungen zu den tatsächlich übergebenen Argumenten passen*) - das sind Probleme, die die entsprechenden C++ Klassen umgehen können (std::string verwaltet seinen Speicher selber, cout erkennt dank Templates und Überladungen automatisch, welchen Typ die übergebenen Variablen haben, ...).
* Boris' Lösung 'printf("%2.2i",zahl);' demonstriert wunderbar, was man da falsch machen kann - %i erwartet einen int-Wert als übergebenen Wert, für float/double benötigst du %f.
(und ich hab' hier schon genug Hilferufe gesehen, die auf der falschen Verwendung der Formatkennungen basierten)
-
hustbaer schrieb:
Bis auf wenige Funktionen/Konstrukte die in C++ wirklich problematisch werden können (z.B. setjmp) funktioniert eigentlich alles tadellos wenn man C und C++ mischt.
Noch eine Ergänzung:
printf & co sind können nicht alles das mit cout & co geht. So kennen die C-Bibliotheken nunmal keine Objekte und lassen sich auch nicht ohne weiteres um diese ergänzen. Die C++ Bibliotheken sind dagegen so geplant, das sie auch für solche Fälle erweiterbar sind (z.B. durch Überladung des Stream-Operators).Das ist für mich neben der Sicherheit ein wesentlicher Grund C und C++ nicht zu mischen.
cu André
-
Also ich hab's jetzt fuer meine Anwendung mal so geloest:
int w = 18; . cout << left << setw(w) << label << fixed << right << setprecision(2) << setw(5) << Rabatt << endl;
Das ist so zwar relativ lang, aber wenn ich diese Routine spaeter mal in einem anderen Programm verwenden will, dann ist - zumindest fuer mich als Anfaenger - das Ganze sehr schoen lesbar.
Durch die Variable "w" kann ich zudem den ganzen Output noch ein wenig verschieben, ohne dabei nennenswerten Aufwand treiben zu muessen.
Und fuer groessere Projekte koennte ich das Ganze ja auch noch in eine kleine Funktion packen und dann nur noch etwas in der Art von
schreibe (w, label value);
Wie gesagt, das ist so das Ergebnis meiner Ueberlegungen, zu denen Ihr wie immer ganz toll beigetragen habt.
Gruss
Geunther
-
Ich habe leider gleich noch mal eine Frage zu meiner Idee mit der Funktion.
Statt
cout << left << setw(w) << "VkBrutto" << fixed << right << setprecision(2) << setw(5) << VkBrutto << endl; cout << left << setw(w) << "Rabatt" << fixed << right << setprecision(2) << setw(5) << Rabatt << endl; . etc ....
habe ich also jetzt die Funktion
bool gbs_print (int &w, string &label, double &value) { cout << left << setw(w) << label << fixed << right << setprecision(2) << setw(5) << value << endl; }
welche ich mit
gbs_print ( w, label, value );
aufrufe, wobei die Inhalte der Variablen "label" und "value" aus einer Datenbank kommen, die ohnhin ausgelesen wird. Das macht insofern also keine zusaetzliche Arbeit.
Problem scheint mir nur zu sein, dass ich jetzt aufpassen muss, das "label" auch wirklich immer vom Typ "double" ist, bevor ich diesen Wert an meine Funktion uebergebe.
Gibt's einen einfachen Weg den Wert fuer "value" jeweils sozusagen automatisch zum Beispiel in "string" umzuwandeln? Dann koennte ich mit beliebigen Typen arbeiten ohne mir gross Gedanken machen zu muessen.
-
Du könntest mit Stringstreams (bzw. boost::lexical_cast) jeden Wert in einen String umwandeln, der einen Ausgabeoperator zur Verfügung stellt (hat allerdings den Nachteil, daß du für die double's schon bei dieser Umwandlung die Nachkommastellen einstellen müsstest). Alternativ kannst du auch mit Templates und Überladungen arbeiten:
template<typename T> gbs_print(int w/*hier brauchst's keine Referenzen*/, const string& label/*const verhindert unbeabsichtige Änderungen*/, const T& value) { cout << left << setw(w) << label << right << setw(5) << value << endl; } gbs_print(int w,const string& label,double value) { cout << left << setw(w) << label << fixed << right << setprecision(2) << setw(5) << value << endl; }
(PS: Ja, Referenzen sind nützlich, aber man kann es damit auch übertreiben :D)
-
gboelter schrieb:
"Sauber genug" ...., heisst das, man koennte es noch eleganter loesen?
Ja - (s.u.)
BorisDieKlinge schrieb:
ich würde sicher noch
printf("%2.2i", zahl);
verwenden;) Die alte C gewohneit
.. nur so sicher nicht.
gboelter schrieb:
Und fuer groessere Projekte koennte ich das Ganze ja auch noch in eine kleine Funktion packen und dann nur noch etwas in der Art von
schreibe (w, label value);
Hallo Günther,
mehr C++-like wäre es, für den 'EKnetto' oder den 'Rabatt' eine eigene Klasse zu erstellen - auch wenn Dir das zunächst vielleicht 'overkilled' erscheint - und innerhalb dieser Klasse den operator<< zu überladen - genau wie asc das schon angedeutet hat. Im Prinzip sähe es so aus:
class Rabatt { public: friend std::ostream& operator<<( std::ostream& out, const Rabatt& rabatt ) { return out << ... << "Rabatt: " << std::setw(5) << ... << rabatt.m_value; } private: double m_value; };
Die Anwendung wäre dann ganz einfach:
Rabatt rabatt; cout << rabatt << endl;
.. und wo immer dies aufgerufen wird, erscheint der Rabatt in der gleichen Art & Weise. Ab Rabatt oder EkPreis die 'richtige' Klasse dafür ist, hängt weniger von der Ausgabe, als vielmehr von der restlichen Struktur Deines Programmes ab.
Gruß
Werner