Nachkommastellen entfernen



  • Hallo,
    ich lese zurzeit das Buch "Der C++ Programmierer" und bin nun bei einer Übungsaufgabe angekommen, bei dessen Lösung ich mir nicht sicher bin, ob diese Variante systemabhängig ist oder nicht.
    Die Übung ist es, ein Format zu programmieren, welches eine Gleitkommazahl in einen String umwandelt. Vorher wird eine Zeichenbreite angegeben, die, wenn sie Größer als der String ist, mit Leerzeichen die nicht benutzten Zeichen befüllt.
    Meine Lösung entspricht der Aufgabenstellung, jedoch habe ich ein wenig getrickst. Um die Nachkommazahl (von 8.5 wäre das 0.5) herauszubekommen, habe ich einfach die double-Variable in eine int-Variable gespeichert. Dabei habe ich mir den Informationsverlust der Nachkommastellen zum Vorteil gemacht. Ich subtrahiere also die Gleitkommazahl nun mit der Ganzzahl und erhalte die Nachkommazahl. 😃
    Meine Frage dabei: Ist diese Variante fehlerhaft und Systemabhängig?

    #ifndef FORMAT_H
    #define FORMAT_H
    
    #include <vector>
    #include <string>
    
    class Format
    {
        public:
            Format(size_t br, size_t nks);
            std::string toString(double d);
        private:
            std::string intInString(int z);
    
            size_t breite;
            size_t nachkommastellen;
    };
    
    #endif // FORMAT_H
    
    #include "Format.h"
    
    Format::Format(size_t br, size_t nks) : breite(br), nachkommastellen(nks) { }
    std::string Format::toString(double d)
    {
        std::string zahl;
        bool negativ = d < 0.0;
        if(negativ)
        {
            d = -d;
            zahl += '-';
        }
    
        int vorkommazahl = d; // d's Nachkommazahlen werden bei einer Zuweisung mit [int] einfach abgeschnitten
        double nachkommazahl = d - vorkommazahl;
        double runden = 0.5;
        for(size_t i = 0; i < nachkommastellen; ++i) { runden /= 10; }
        nachkommazahl += runden; // Die Nachkommazahl runden
    
        zahl += intInString(vorkommazahl) + ','; // intInString(int) wandelt eine Ganzzahl in einen [string]-Datentyp um
    
        // Umwandeln der Nachkommazahl in einen [string]-Datentyp
        for(size_t i = 0; i < nachkommastellen; ++i)
        {
            nachkommazahl *= 10;
            int ziffer = nachkommazahl;
            zahl += ziffer + '0';
            nachkommazahl -= ziffer;
        }
    
        std::string ergebnis;
        if(breite < zahl.length()) { breite = zahl.length(); } // Wenn die Breitenangabe zu klein war, dann wird sie angepasst
        for(size_t i = 0; i < breite - zahl.length(); ++i) { ergebnis += ' '; } // Ergänze Leerzeichen
        ergebnis += zahl;
    
        return ergebnis;
    }
    std::string Format::intInString(int z)
    {
        std::string zahl;
        // Jede Ziffer in den String anhängen.
        // Die Reihenfolge der Ziffern ist jedoch nach der Ausführung der Schleife umgekehrt.
        while(z > 0)
        {
            int ziffer = z % 10;
            zahl += ziffer + '0';
            z /= 10;
        }
        // Zeichenpositionen inventieren
        for(size_t i = 0; i < zahl.length() / 2; ++i)
        {
            const char CH = zahl[i];
            zahl[i] = zahl[zahl.length() - 1 - i];
            zahl[zahl.length() - 1 - i] = CH;
        }
    
        return zahl;
    }
    
    #include <iostream>
    #include "Format.h"
    
    using namespace std;
    
    int main()
    {
        Format f(12, 2);
        cout << f.toString(789.906625) << endl;
        cout << f.toString(23.766);
    
        return 0;
    }
    


  • BlauesShirt schrieb:

    Meine Frage dabei: Ist diese Variante fehlerhaft und Systemabhängig?

    Nö, so ist das im Standard definiert.

    N3337, 4.9.1:

    A prvalue of a floating point type can be converted to a prvalue of an integer type. The conversion truncates;
    that is, the fractional part is discarded.

    Schlau getrickst 👍



  • BTW: An die "Pros", ist das eig. eine saubere C++98-Variante? Ich hab das Gefühl, Gugelmoser oder Werner hatten irgendeinen Trick oder so... 😕

    template<typename Type>
    typename std::enable_if<std::is_floating_point<Type>::value, std::string>::type toString(Type const t)
    {
            std::ostringstream stream;
            stream << std::fixed << std::setprecision(std::numeric_limits<Type>::digits10) << t;
            std::string str = stream.str();
            return str.substr(0, str.find_last_not_of("0") + 1);
    }
    


  • Sone schrieb:

    BTW: An die "Pros", ist das eig. eine saubere C++98-Variante? Ich hab das Gefühl, Gugelmoser oder Werner hatten irgendeinen Trick oder so... 😕

    template<typename Type>
    typename std::enable_if<std::is_floating_point<Type>::value, std::string>::type toString(Type const t)
    {
            std::ostringstream stream;
            stream << std::fixed << std::setprecision(std::numeric_limits<Type>::digits10) << t;
            std::string str = stream.str();
            return str.substr(0, str.find_last_not_of("0") + 1);
    }
    

    Nö, also ich wars mal nicht und mir fällt auch nichts besseres ein. Aber bin auch kein Pro. 🤡


  • Mod

    BlauesShirt schrieb:

    Meine Frage dabei: Ist diese Variante fehlerhaft und Systemabhängig?

    Den Fall, dass dein Ausgangswert zu groß für ein Integer ist, behandelst du nicht.

    fmod(d,1)
    


  • Könnte man das auch per

    precision();

    machen?



  • gutttenberggg schrieb:

    Könnte man das auch per

    precision();

    machen?

    Du meinst, den ostream-Member?

    So hab ich das doch gemacht:

    std::cout << std::setprecision(X) /* Festlegen, wieviele Nachkommastellen wir möchten 
                                        (Achtung, funktioniert nur, nachdem das floatingfield Format-Flag auf fixed gesetzt wurde! 
                                         Sonst heißt es nur, wieviele Signifikante Stellen ausgegeben werden sollen). */
              << std::fixed           /*Hier wird das oben beschriebene Flag auf fixed gesetzt. Das heißt, wenn wir eine Fließkommazahl mit den insertion-Operatoren in den Stream schieben,
                                        wird sie definitiv in der Festkomma-Notation in den Stream geschrieben. */
    


  • man bin ich blind oder was 😮

    sorry, natürlich 🙂


Anmelden zum Antworten