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:

    http://www.willemer.de/informatik/cpp/iostream.htm

    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


Anmelden zum Antworten