Klasse zum Formatieren von Zahlen



  • Aufgabe:
    Schreiben Sie eine Klasse Format zum Formatieren von Zahlen. Benutzungsbeispiel:

    // Konstruktion des Format-Objekts
    Format f(12, 3); // Ausgabe 12 Zeichen breit, 3 Nachkommastellen
    cout << f.toString(789.906625) << ’\n’; // Benutzung
    cout << f.toString(-123456789.906625) << ’\n’;

    Das Ergebnis soll #####789,907 im ersten Fall und -123456789,907 im zweiten Fall sein,
    wobei # hier für ein Leerzeichen steht. Im zweiten Fall reichen 12 Plätze zur Darstellung
    aller Ziffern nicht aus. Die Weite wird daher automatisch erweitert, um Informationsver-
    lust zu vermeiden.

    Musterlösung:
    main.cpp:

    #include "format.h"
    #include <iostream>
    using namespace std;
    
    int main() {
    
      Format f(12, 3);
      cout << "789.906625        :" << f.toString(789.906625) << '\n';
      cout << "-123456789.906625 :" << f.toString(-123456789.906625) << '\n';
      cout << "-0,00123456789    :" << f.toString(-0.00123456789) << '\n';
      cout << "0,00              :" << f.toString(0.00) << '\n';
      cout << "-12345.6789906625 :" << f.toString(-12345.6789906625) << '\n';
      cout << "1.00000           :" << f.toString(1.0) << '\n';
    
      Format fi(12, 0);
    
      cout << "123               :" << fi.toString(123) << '\n';
      cout << "-123456789.906625 :" << fi.toString(-123456789.906625) << '\n';
    }
    
    format.h:
    #ifndef FORMAT_H
    #define FORMAT_H
    #include <string>
    
    class Format {
    public:
      Format(unsigned int weite, unsigned int nachk);
      std::string toString(double d) const;
    
    private:
      unsigned int weite;
      unsigned int nachkommastellen;
    };
    #endif
    

    format.h:

    #ifndef FORMAT_H
    #define FORMAT_H
    #include <string>
    
    class Format {
    public:
      Format(unsigned int weite, unsigned int nachk);
      std::string toString(double d) const;
    
    private:
      unsigned int weite;
      unsigned int nachkommastellen;
    };
    #endif
    

    format.cpp:

    #include "format.h"
    #include <iostream>
    using namespace std;
    
    Format::Format(unsigned int w, unsigned int nk)
        : weite{w}, nachkommastellen{nk} {
      if (nachkommastellen > 16) {
        nachkommastellen = 16;
      }
      if (weite < nachkommastellen) {
        weite = nachkommastellen + 1;
      }
    }
    
    string Format::toString(double d) const {
      string ergebnis;
      bool negativ{false};
      if (d < 0.0) {
        negativ = true;
        d = -d;
      }
      // Rundung
      double rund{0.5};
      for (unsigned int i = 0; i < nachkommastellen; ++i) {
        rund /= 10.0;
      }
      d += rund;
    
      // Mit der folgenden Normierung (d.h. Zahl beginnt mit 0,..) wird
      // erreicht, dass die
      // Anzahl der Stellen vor dem Komma bekannt ist (Stellenwert).
      int stellenwert = 0;
      // Zahl normieren, falls >=1
      while (d >= 1.0) {
        ++stellenwert;
        d /= 10.0;
      }
      if (stellenwert == 0) {
        ergebnis += '0';  // wenigstens eine 0 vor dem Komma
      }
    
      // Die Zahl wird sukzessive mit 10 multipliziert, die jeweils
      // erste
      // Ziffer zunächst
      //  ermittelt (zif), dann abgetrennt und an den Ergebnis-String
      //  gehängt usw.
      // Zahl abarbeiten
      do {
        if (stellenwert == 0) {
          ergebnis += ',';  // Komma
        }
        d *= 10.0;
        int zif = static_cast<int>(d);
        d -= zif;
        ergebnis += zif + '0';
        --stellenwert;
      } while (static_cast<int>(nachkommastellen) + stellenwert > 0);
    
      if (negativ) {
        ergebnis = '-' + ergebnis;
        ;
      }
      int diff = weite - ergebnis.length();
      for (int i = 0; i < diff; ++i) {
        ergebnis = " " + ergebnis;
      }
      return ergebnis;
    }
    

    Konsole:
    (hier fehlen die Leerzeichen)
    789.906625 : 789,907
    -123456789.906625 :-123456789,907
    -0,00123456789 : -0,001
    0,00 : 0,000
    -12345.6789906625 : -12345,679
    1.00000 : 1,000
    123 : 123
    -123456789.906625 : -123456790
    Betõtigen Sie die <RETURN> Taste, um das Fenster zu schlie▀en...

    Diese Lösung kann ich nicht nachvollziehen. Vielleicht kann mir jemand dabei helfen.

    Warum wird bei der Textausgabe in Zeile 9 ein Punkt und in Zeile 10 ein Komma verwendet?
    Ich meine doch dass die Werte alle mit Punkt eingelesen und mit Komma ausgegeben werden.

    In format.cpp steht in Zeile 23:

    double rund{0.5};
    

    Welche Bedeutung hat hier 0.5?
    Warum wird 0.5 dann in der Schleife immer wieder durch 10 geteilt?

    Und den Teil dannach verstehe ich auch nicht.
    Wie mache ich hier nur den ersten Schritt um irgendwann dieses Programm zu verstehen?



  • @theAnfänger77 sagte in Klasse zum Formatieren von Zahlen:

    Warum wird bei der Textausgabe in Zeile 9 ein Punkt und in Zeile 10 ein Komma verwendet?

    Weil der Schreiberling schlicht inkonsequent ist.

    @theAnfänger77 sagte in Klasse zum Formatieren von Zahlen:

    Warum wird 0.5 dann in der Schleife immer wieder durch 10 geteilt?

    Um die 0.5 Schritt für Schritt dahin zu verschieben wo gerundet werden soll.



  • Danke, das mit der 0.5 verstehe ich jetzt.
    Weil hinten abgeschnitten wird muss im Falle einer Aufrundung die letzte Zahl um 1 erhöht werden.


Log in to reply