Das Konzept der Rundung kennt man grundsätzlich. Aber versuchen wir es etwas systematischer zu erfassen.
Man hat eine Menge von Zahlen und eine Teilmenge davon, deren Elemente in der verwendeten Programmierumgebung dargestellt werden. Dazu hat man noch eine Metrik . Man verlangt normalerweise noch gewisse Eigenschaften von :
- Positive Definitheit:
- Symmetrie:
- Dreiecksungleichung:
Typischerweise sind die Zahlen, mit denen wir uns meistens beschäftigen, in der Welt der reellen und komplexen Zahlen gedacht, man kann also fast immer sicher sein, dass ist, meistens sogar oder wenn wir ehrlich sind sogar . Dann ist normalerweise . Wer die komplexen Zahlen noch nicht kennt, denke einfach an reelle und rationale Zahlen, das ist das, womit wir normalerweise bewusst zu tun haben. Dabei sind natürlich Konzepte wie Rundung speziell in -adischen Zahlen hochinteressant, aber dafür muss ich die erstmal erklären und das lasse ich heute…
Was stellen wir uns nun unter einer Rundung vor?
Vielleicht eine Abbildung
,
die mit gewissen Nebenbedingungen für jedes x jeweils so gewählt wird, dass minimal ist.
Die Nebenbedingungen brauchen wir einerseits, um es eindeutig zu machen, wenn mehrere Werte existieren, für die minimal ist. Der klassische Fall ist das Runden auf ganzzahlige Werte und die Frage mit der . Wenn eine Teilmenge der reellen Zahlen ist, was ja „meistens“ der Fall ist, hat man eine Anordung. Da kommen dann die folgenden Constraints zum Tragen (Beispiel immer mit Rundung auf ganze Zahlen):
- ROUND_UP
- Z.B. und und
- ROUND_DOWN
- Z.B. und und
- ROUND_CEILING
- Z.B. und und
- ROUND_FLOOR
- Z.B. und und
- ROUND_HALF_UP
- Minimiere , aber wenn es mehrere optimale Werte für gibt, wähle den am weitesten von 0 entfernten, z.B. und und und
- ROUND_HALF_DOWN
- Minimiere , aber wenn es mehrere optimale Werte für gibt, wähle den am nächsten an 0, z.B. und und und
- ROUND_HALF_CEILING
- Minimiere , aber wenn es mehrere optimale Werte für gibt, wähle den größten, z.B. und und und
- ROUND_HALF_FLOOR
- Minimiere , aber wenn es mehrere optimale Werte für gibt, wähle den kleinesten, z.B. und und und
- ROUND_HALF_EVEN
- Minimiere , aber wenn es mehrere optimale Werte für gibt, wähle den mit gerader Endziffer. Achtung, dieser Constraint ist im „klassischen“ Fall anwendbar, aber nicht allgemeingültig. Z.B.: und und und und
- ROUND_UNNECESSARY
- Dieser Constraint ist im mathematischen Sinne nicht geeignet (oder nur mit hässlichen Verrenkungen), aber programmatisch können wir das: Wir nehmen und schmeißen eine Exception wenn nicht schon gilt.
Typischerweise denken wir im Dezimalsystem und dann wählen wir eine Zehnerpotenz mit , also . Nun ist einfach
,
also umgangsprachlich sind in alle Zahlen aus mit maximal Stellen nach dem Komma. Diese Rundung funktioniert ganz gut mit so etwas wie LongDecimal in Ruby oder BigDecimal in Scala oder Java, wobei BigDecimal weniger Rundungsmodi anbietet als LongDecimal für Ruby.
Nun kommen wir zur Restklassenrundung. Wir gehen wieder von dieser Zehnerpotenz aus. Dann brauchen wir noch eine natürlich Zahl und eine Menge von Resten . Nun ist
.
Das bedeutet, wenn wir mit Nullen auf die angegebene Anzahl von Nachkommastellen auffüllen, das „Komma“ (normalerweise als „.“ geschrieben) weglassen und dann diese Zahl mit Rest durch teilen, der dabei herauskommende Rest in liegt.
In diesem Fall wird es mit dem ROUND_HALF_EVEN eventuell schwierig, da es undefiniert oder mehrdeutig werden kann. Aber wir müssen auch den Fall abdecken, dass die 0 nicht in ist und Regeln angeben, wohin die 0 gerundet werden soll. Die Kandidaten sind hier mit selbsterklärenden Namen versehen:
- ZERO_ROUND_TO_PLUS
- ZERO_ROUND_TO_MINUS
- ZERO_ROUND_TO_CLOSEST_PREFER_PLUS
- ZERO_ROUND_TO_CLOSEST_PREFER_MINUS
- ZERO_ROUND_UNNECESSARY
Ein wichtiger Anwendungsfall ist hier und . So kann man in der Schweiz Geldbeträge auf Vielfache von 5 Rappen (0.05 CHF) runden. Dies wurde in Rundung bei Geldbeträgen bereits genauer beschrieben.
Schreibe einen Kommentar