Robert Bamler: Mathematik: Wie erstelle ich Skala mit "runden" Einträgen?

Beitrag lesen

Hallo Andreas & Co.,

jetzt wurde ja schon eine ganze Menge geantwortet. Trotzdem möchte ich versuchen, mich auch noch "einzumischen", weil ich das Problem interessant finde. Vorab: ich kenne mich in PHP nicht aus, deswegen schreibe ich die Formeln in einer "Mischung aus Mathematik und Klartext".

Und nochwas, ich überlege gerade, wie ich sinnvollerweise eine Skala implemementiere.

Ich würde das so angehen:

Gegeben ist ein Minimalwert und ein Maximalwert der Gebote. Daraus errechnet sich die Differenz der Gebote. Da der kleinste Balken immer noch eine Mindesthöhe > 0 haben soll, muss vom Minimalwert noch ein bestimmter Wert abgezogen werden. Damit dieser Wert in der Grafik immer gleichhoch erscheint, muss er proportional zur *Differenz* sein, da die Differenz ja auf eine bestimmte Pixelhöhe "gezerrt" wird. Wenn das Minimalgebot und das Maximalgebot also sehr unterschiedlich sind, wird "viel Geld" auf kleinem Raum dargestellt. Ein Pixel in der Grafik repräsentiert also mehr Cents, als wenn sich die Gebote kaum im Preis unterscheiden würden. Daher stellt auch der Platz, der unter dem letzten Gebot zur Ästhetik freigelassen werden soll, mehr Geld dar. Es muss also mehr vom Minimalwert abgezogen werden, als wenn die Gebote sehr nahe beieinander liegen würden. (Ich hoffe, das kann man jetzt verstehen.)

Gegeben: maxwert, minwert;  # Werte des höhsten und niedrigsten Gebots
Gesucht:
 einheit,         # "runde" Zahl von Euro zwischen zwei Markierungen auf der y-Achse
 intervallanz,    # Anzahl der Intervalle, in die die y-Achse eingeteilt werden soll
                  # (ungefähr 10)
 maxwert, minwert # "gerundeter" Maximal- und Minimalwert auf der y-Achse des Diagramms

minwert = minwert - (maxwert-minwert)*0.1;   # unten 10% Platz lassen
if (minwert < 0)  minwert = 0;               # Minimalwert soll nie kleiner als 0 sein.

differenz = maxwert - minwert;       # Achtung: kann 0 werden, wenn nur ein Gebot vorhanden

Diese Differenz soll jetzt in 10 "runde" Intervalle eingeteilt werden. Hier ergibt sich das Problem aus der Definition von "rund". Ich würde das einmal so bezeichnen: Die Differenz soll in Intervalle eingeteilt werden, bei denen im Dezimalsystem nur die erste Ziffer ungleich 0 sein darf. Aus 2345 würde also 2000, aus 465 würde 500 und aus 9821 würde 10000. Der "Rundungsfehler" ist also relativ zur Ausgangszahl gering gehalten. (Wenn das noch zu grob ist, kannst du dir ja überlegen, ob du nicht den ersten beiden Stellen erlaubst, ungleich 0 zu sein. Also 2345 --> 2300, 465 --> 470 und 9821 --> 9800. In diesem Fall müsstest du potenz im folgenden code durch 10 teilen.)

Dann könnte man so "runden":

potenz = 10 ^ abrunden(log(nichtrund));       # zu rundender Wert sollte ungleich 0 sein
ersteZiffer = runden(nichtrund/potenz);       # Kann Werte von 1-10 annehmen (nicht 0);
rund = ersteZiffer*potenz;

Wobei:

  • ^:              "Hoch" (Potenzieren)
  • abrunden(wert): wert wird auf die nächst kleinere ganze Zahl gerundet
  • log(wert):      Logarithmus zur Basis 10
  • runden(wert):   "kaufmännisches" Runden auf ganze Zahlen
                      (bis .5 abrunden, ab .5 inklusive aufrunden)

Du würdest also die weiter oben errechnete Differenz durch 10 teilen und das Ergebnis dieses Quotientens anschließend wie oben runden. Das gerundete Ergebnis möchte ich jetzt "Einheit" nennen. Eine Einheit gibt an, wie viel Euro zwischen zwei Markierungen auf der y-Achse liegen.

einheit = differenz/10;
potenz = 10 ^ abrunden(log(einheit));       # zu rundender Wert sollte ungleich 0 sein
ersteZiffer = runden(einheit/potenz);       # Kann Werte von 1-10 annehmen (nicht 0);
einheit = ersteZiffer*potenz;

Anschließend solltest du nocheinmal überprüfen, ob es wirklich sinnvoll ist, die Skala in genau 10 Intervalle aufzuteilen. Unter bestimmten Bedingungen kann es nämlich sein, dass durch das Runden eine Aufteilung in 9 oder 11 Intervalle sinvoller ist. Die Anzahl der Intervalle, in die die Skala zerteilt werden soll, nenne ich "inntervallanz":

intervallanz = aufrunden(differenz/einheit);    # einheit sollte ungleich 0 sein

Wobei aufrunden(wert) das Runden auf die nächsthöhere ganze Zahl sein soll.

Daraus errechnet sich ein neuer Wert für die Differenz aus dem Maximal- und Minimalwert: Die Differenz stellt jetzt den Geldbereich dar, der auf der y-Achse angezeigt wird. Sie errechnet sich also so:

differenz = intervallanz * einheit;

Jetzt musst du noch den Maximalwert so setzen, dass er ein Vielfaches von potenz ist, aber nicht kleiner und auch nur möglichst wenig größer wird:

maxwert = aufrunden(maxwert/potenz)*potenz;      # potenz ist ungleich 0

Der Minimalwert errechnet sich dann wie folgt:

minwert = maxwert - differenz;                   # minwert sollte nie kleiner als 0 werden

Wenn ich jetzt nichts übersehen habe, sollte gelten:
differenz = maxwert - minwert = einheit * intervallanz;
Außerdem sollte der Maximalwert nicht kleiner und der Minimalwert nicht größer geworden sein.

Bitte sagt mir, wenn euch ein Denkfehler auffällt. Ich habe das nämlich noch nicht getestet, könnte mir aber vorstellen, dass es so in etwa funktioniert.

Das ganze noch mal zusammengeschrieben:

#----------------------------------------------------------

minwert = minwert - (maxwert-minwert)*0.1;   # unten 10% Platz lassen
if (minwert < 0)  minwert = 0;               # Minimalwert soll nie kleiner als 0 sein.
differenz = maxwert - minwert;       # Achtung: kann 0 werden, wenn nur ein Gebot vorhanden

einheit = differenz/10;
potenz = 10 ^ abrunden(log(einheit));       # zu rundender Wert sollte ungleich 0 sein
ersteZiffer = runden(einheit/potenz);       # Kann Werte von 1-10 annehmen (nicht 0);
einheit = ersteZiffer*potenz;

intervallanz = aufrunden(differenz/einheit);    # einheit sollte ungleich 0 sein

differenz = intervallanz * einheit;

maxwert = aufrunden(maxwert/potenz)*potenz;      # potenz ist ungleich 0
minwert = maxwert - differenz;                   # minwert sollte nie kleiner als 0 werden

#----------------------------------------------------------

Robert

--
Dieser Beitrag wurde zu 100% aus ganzen Sätzen hergestellt und ist biologisch abbaubar.