C++Guns – RoboBlog

02.02.2018

C++ Guns: Generic Data Type Design Pattern - Teil 2

Filed under: Allgemein — Tags: — Thomas @ 16:02

Weiter gehts mit der Anwendung meiner Idee alle einfachen Datentypen als std::array oder std::tuple abzubilden. Wie im ersten Teil schon für den Point2D Datentyp realisiert.

Jetzt werde ich einen Range Datentyp bauen. Dieser besteht einfach aus zwei Zahlen die eine obere und untere Grenze von etwas angibt. Zusätzlich ist die Spanne zwischen obere und untere Grenze interessant. Dies ist aber eine abgeleitete Größe und darf deshalb nicht als gespeichert werden, sondern soll extra berechnet werden.

struct Range : public std::array<double,2>
{
  const auto& lower() const {
    return operator[](0);
  }

  const auto& upper() const {
    return operator[](1);
  }

  const auto size() const {
    return upper()-lower();
  }
}

So, die Intitialisierung erfolgt über eine Liste. Der Zugriff einheitlich über Funktionen. Sowohl für gespeicherte Werte sowie für abgeleitete. Das ist schon mal gut.

Hässliche Member Variablen fallen mit diesem Entwurfsmuster weg. Damit muss man sich und auch nicht mehr überlegen wie man sie nennt. Mit Unterstrich, Groß/Kleinschreibung oder ganz kryptisch und verkrüppelt. Nein, die Entscheidung muss überhaupt nicht mehr gefällt werden.

Da dieses Beispiel doch recht einfach war, versuchen wir es doch mal mit den Stochastischen Momenten.
Also einen Datentyp welche Mittelwert, Varianz und Standardabweichung bereitstellt. Nun kann man aus einer vorher erstellten Summe und der Anzahl der Summanden diese drei Werte immer berechnen. Aber das erscheint mir zu aufwendig und irgendwie nicht richtig. Daher tendiere ich dazu, avg var und std direkt in dem Datentyp abzuspeichern.

Versuchen wir es:

struct StochastikMoment : public std::array<3,double>
{
  template<typename Container>
  StochastikMoment(const Container& data) {
    operator[0] = sum(data)/data.size();
    operator[1] = ...;
    operator[2] = std::sqrt(operator[1]);
  }

  const auto& avg() const {
    return operator[0];
  }

  const auto& var() const {
    return operator[1];
  }

  const auto& std() const {
    return operator[2];
  }
}

Die Initialisierung kann wieder über eine Liste erfolgen, wenn nötig. Aber im Normalfall werden die Momente aus vorgegebenen Daten berechnet. Den Algorithmus dafür spare ich mir.
Der Zugriff Erfolg wie gewohnt über Funktionen. Ich denke an diesem Beispiel wird klar, warum nur const Funktionen in diesem Entwurfsmuster Sinn machen. Die Standardabweichung ist streng verbunden mit der Varianz. Und die Varianz hängt stark vom Mittelwert ab. Es macht einfach keinen Sinn, Mittelwert und Varianz algorithmus zu bestimmen aber die Varianz manuell vorzugegen. Diese drei Werte hängen voneinander ab und treten dementsprechend immer zusammen auf.

Hätte ich mich bei diesem Datentyp anders entschieden und die drei Werte immer wieder berechnet, und die Summe gespeichert, dann wäre das doch auch ganz klar. Wenn man den Mittelwert berechnet, kann man ihn nicht über avg() Setzen.

Ich frage mich ob diese Art und Weise allgemeingültig für alle einfachen Datentypen ist.

Auf jeden Fall ist das serialisieren dadurch einfach. Weiter im dritten Teil.

No Comments

No comments yet.

RSS feed for comments on this post.

Sorry, the comment form is closed at this time.

Powered by WordPress