Sie sind zurzeit offline. Es wird auf die erneute Herstellung einer Internetverbindung gewartet.

Implementierung benutzerdefinierter Rundungsverfahren

Dieser Artikel wurde zuvor veröffentlicht unter D44055
Dieser Artikel ist eine Übersetzung des folgenden englischsprachigen Artikels der Microsoft Knowledge Base:
196652 How To Implement Custom Rounding Procedures
Zusammenfassung
In Microsoft-Produkten stehen diverse verschiedene Rundungsalgorithmen zur Verfügung. Zu diesen Rundungsalgorithmen zählen zum Beispiel die arithmetische Rundung in der Excel-Arbeitsblattfunktion "Round()" sowie die bankübliche in den Funktionen "CInt()", "CLng()" und "Round()" von Visual Basic für Applikationen (Bankers Runden). In diesem Artikel wird beschrieben, wie die diversen Rundungsfunktionen von Visual Basic für Applikationen wirken. Außerdem enthält dieser Artikel Beispielfunktionen, bei denen die verschiedenen Rundungsalgorithmen implementiert werden.
Weitere Informationen

Erklärung des Begriffs "Rundung"

Sie müssen eine Rundung durchführen, wenn Sie einen präzisen Zahlenwert in einen weniger präzisen umwandeln möchten. Der häufigste Fall ist die Umwandlung einer Gleitkommazahl in eine ganze Zahl.

Abrunden

Die einfachste Form der Rundung ist das Abschneiden der Kommastellen. Alle Stellen nach dem gewünschten Präzisionsgrad werden einfach ignoriert. Die VBA-Funktion "Fix()" ist ein Beispiel für diese Art der Rundung. So ergibt Fix(3.5) beispielsweise 3 und Fix(-3.5) ergibt -3.

Die Funktion "Int()" rundet bis zu der höchsten ganzen Zahl ab, die kleiner ist als der Ausgangswert. Bei positiven Zahlen wirken die Funktionen "Int()" und "Fix()" gleich - sie schneiden Kommastellen ab - ergeben jedoch verschiedene Resultate bei negativen Zahlen: Int(-3.5) ergibt -4.

Die Funktion "Fix()" ist ein Beispiel für symmetrische Rundung, weil sie den Absolutwert von positiven und negativen Zahlen auf die gleiche Art und Weise beeinflusst. Die Funktion "Int()" ist ein Beispiel für asymmetrische Rundung, weil sie den Absolutwert positiver und negativer Zahlen unterschiedlich beeinflusst.

In Excel gibt es ähnliche Funktionen für die Tabellenkalkulation: "Int()", "Floor()" und "RoundDown()". "Int()" hat die gleiche Wirkung wie die Funktion "Int()" in Visual Basic für Applikationen. "Floor()" schneidet positive Werte ab, funktioniert bei negativen Zahlen jedoch nicht. Die Funktion "RoundDown()" entspricht in ihrer Wirkungsweise der VBA-Funktion "Fix()".

In Microsoft SQL Server gibt es eine Funktion "Round()", die wirken kann wie die VBA-Funktion "Fix()". Außerdem hat SQL Server eine Funktion "Floor()", die in ihrer Wirkung der VBA-Funktion "Int()" entspricht.

Aufrunden

Sowohl in SQL Server als auch in Excel gibt es eine Funktion mit dem Namen "Ceiling()" (Obergrenze), bei der Bruchwerte immer auf den nächsthöheren Wert aufgerundet werden.

Visual Basic für Applikationen hat keine entsprechende Aufrundungsfunktion. Für negative Zahlen können jedoch die Funktionen "Fix()" und "Int()" auf verschiedene Weise zum Aufrunden eingesetzt werden.

"Fix()" rundet in Richtung 0 (im eigentlichen Sinne aufwärts, aber abwärts in Bezug auf den Absolutwert). Fix(-3.5) ergibt -3,5.

"Int()" rundet weg von 0 (aufwärts in Bezug auf den Absolutwert, aber abwärts im eigentlichen Sinn). Int(-3.5) ergibt -4.

Arithmetische Rundung

Wenn immer entweder auf- oder abgerundet wird, liegt das Ergebnis nicht notwendigerweise am nächsten an der ursprünglichen Zahl. Wenn Sie zum Beispiel 1,9 auf 1 abrunden, ist die Differenz erheblich größer als bei einer Aufrundung auf 2. Es ist also einleuchtend, dass Zahlen von 1,6 bis 2,4 auf 2 gerundet werden sollten.

Was macht man jedoch mit dem Wert 1,5, bei dem die Differenz zu 1 und 2 jeweils gleich ist? Hier gilt die Konvention, solche Werte aufzurunden.

Sie können für diese auf halbem Wege liegenden Nummern eine symmetrische Rundung festlegen, bei der -0,5 zu -1 abgerundet wird, oder eine asymmetrische Rundung, bei der -0,5 zu 0 aufgerundet wird.

Bei den folgenden Funktionen wird eine symmetrische arithmetische Rundung angewendet:
Die Excel-Tabellenkalkulationsfunktion "Round()".
Die SQL Server-Funktion "Round()" kann für die symmetrische arithmetische Rundung eingesetzt werden.

Bei der folgenden Funktion wird eine asymmetrische arithmetische Rundung angewendet:
Methode "Round()" der Java-Mathematikbibliothek.

In Visual Basic für Applikationen gibt es keine Funktion für die arithmetische Rundung.

Bankübliche Rundung (Bankers Runden)

Wenn man gerundete Werte addiert und Werte wie 1,5 oder 2,5 immer in dieselbe Richtung gerundet werden, entsteht eine Abweichung, die mit der Anzahl der addierten Werte immer stärker wird. Eine Möglichkeit, diese Abweichung auf ein Minimum zu begrenzen, ist die bankübliche Rundung.

Bei diesem Rundungsverfahren werden Werte wie 1,5 oder 2,5 mal auf- und mal abgerundet. Die Konvention bei dieser Art der Rundung ist, immer auf die nächste gerade Zahl zu runden, so dass 1,5 und 2,5 zu 2 gerundet werden und 3,5 sowie 4,5 zu 4 gerundet wird. Es handelt sich hierbei um eine symmetrische Rundung.

In Visual Basic für Applikationen führen die folgenden Funktionen die bankübliche Rundung aus: CByte(), CInt(), CLng(), CCur() und Round().

Es gibt keine Excel-Tabellenkalkulationsfunktionen für die bankübliche Rundung.

Zufallsrundung

Auch bei der banküblichen Rundung kann das Gesamtergebnis erhebliche Abweichungen aufweisen. Sie können diese Abweichung weiter reduzieren, indem Werte wie 1,5 oder 2,5 streng nach dem Zufallsprinzip auf- oder abgerundet werden. In diesem Fall kann die Abweichung selbst bei absichtlich beeinflussten Daten minimiert werden. Bei einer Zufallsrundung von nach dem Zufallsprinzip verteilten Daten kann die Abweichung im Einzelfall jedoch sogar größer sein als bei der banküblichen Rundung. Die Zufallsrundung kann bei identischen Daten zu zwei unterschiedlichen Gesamtergebnissen führen.

In Microsoft-Produkten gibt es kein Verfahren zur Zufallsrundung.

Abwechselnde Rundung

Bei der abwechselnden Rundung werden Werte wie 1,5 oder 2,5 abwechselnd auf- oder abgerundet.

In Microsoft-Produkten gibt es kein Verfahren zur abwechselnden Rundung.

Inkonsistente Implementierung der Funktion "Round()"

Die Implementierung der Funktion "Round()" ist in den verschiedenen Microsoft-Produkten aus historischen Gründen nicht konsistent.

In der folgenden Tabelle werden Produkt und Rundungsverfahren gegenübergestellt:
   Produkt                             Implementierung   ----------------------------------------------------------------------   Visual Basic für Applikationen 6.0         Bankübliche Rundung   Excel-Tabellenblatt                              Symmetrische arithmetische Rundung   SQL Server                                         Entweder symmetrische arithmetische Rundung                                                             oder symmetrisches Abrunden (Fix) in                                                             Abhängigkeit von den Argumenten   Java-Mathematikbibliothek                    Asymmetrische arithmetische Rundung				

Die Funktion "Round()" in Visual Basic 6.0 und Visual Basic für Applikationen 6.0 führt die bankübliche Rundung durch. Bei dieser Funktion gibt es ein optionales zweites Argument, das die Anzahl der Dezimalstellen festlegt, auf die gerundet werden soll:
   Debug.Print Round(2.45, 1) returns 2.4.				

Beispieldaten

Die folgende Tabelle zeigt anhand von Beispieldaten die Auswirkungen verschiedener Rundungsverfahren auf die daraus resultierenden Gesamtergebnisse.
   Zahl/  Int./Fix/Ceiling/Asym. Arith./Sym. Arith./Bank/    Zufall/Abw.   ---------------------------------------------------------------------   -2.6   -3   -2  -2      -3          -3           -3       -3     -3   -2.5   -3   -2  -2      -2          -3           -2       -2     -3   -2.4   -3   -2  -2      -2          -2           -2       -2     -2   -1.6   -2   -1  -1      -2          -2           -2       -2     -2   -1.5   -2   -1  -1      -1          -2           -2       -1     -1   -1.4   -2   -1  -1      -1          -1           -1       -1     -1   -0.6   -1    0   0      -1          -1           -1       -1     -1   -0.5   -1    0   0       0          -1            0       -1     -1   -0.4   -1    0   0       0           0            0        0      0    0.4    0    0   1       0           0            0        0      0    0.5    0    0   1       1           1            0        1      1    0.6    0    0   1       1           1            1        1      1    1.4    1    1   2       1           1            1        1      1    1.5    1    1   2       2           2            2        1      1    1.6    1    1   2       2           2            2        2      2    2.4    2    2   3       2           2            2        2      2    2.5    2    2   3       3           3            2        3      3    2.6    2    2   3       3           3            3        3      3				

Gesamtergebnis für alle Zahlen:
   Zahl  /Int./Fix/Ceiling/Asym. Arith./Sym. Arith./Bank/    Zufall/Abw.   ---------------------------------------------------------------------   0.0    -9   0   9       3            0           0        1      0				

Gesamtergebnis für alle negativen Zahlen:
   Zahl  /Int./Fix/Ceiling/Asym. Arith./Sym. Arith./Bank/    Zufall/Abw.   ---------------------------------------------------------------------   -13.5  -18  -9  -9      -12          -15         -13      -13    -14				

Gesamtergebnis für alle positiven Zahlen:
   Zahl  /Int./Fix/Ceiling/Asym. Arith./Sym. Arith./Bank/    Zufall/Abw.   ---------------------------------------------------------------------   13.5   9    9   18      15           15          13       14     14				

Die Tabelle zeigt die Differenzen, die bei den verschiedenen Rundungsverfahren in Bezug auf das Gesamtergebnis entstehen. Bei nach dem Zufallsprinzip verteilten positiven und negativen Zahlen, ergeben die Funktion "Fix()", die symmetrische arithmetische Rundung, die bankübliche Rundung und die abwechselnde Rundung die geringste Abweichung vom tatsächlichen Gesamtergebnis, wobei die Zufallsrundung jedoch nur unwesentlich ungenauer ist.

Sind die Zahlen jedoch entweder alle negativ oder alle positiv, ergeben die bankübliche Rundung, die abwechselnde Rundung und die Zufallsrundung die geringste Abweichung vom tatsächlichen Gesamtergebnis.

Beispiel für benutzerdefinierte Rundungsfunktionen

Die Beispielcodes für Funktionen aus dem nachstehenden Abschnitt "Auflistung der Funktionen" zeigen praktische Anwendungen für alle in diesem Artikel beschriebenen Rundungsverfahren.

Diese Funktionen sind:
   AsymDown      Rundet Zahlen asymmetrisch ab - ähnelt der Funktion "Int()".                 Bei negativen Zahlen wird das Ergebnis noch negativer.   SymDown       Rundet Zahlen symmetrisch ab - ähnelt der Funktion "Fix()".                 Beschneidet alle Zahlen in Richtung 0.                 Wirkt für positive Zahlen wie "AsymDown".   AsymUp        Rundet Stellen hinter dem Komma asymmetrisch auf.                 Wirkt für negative Zahlen wie "SymDown".                 Ähnelt der Funktion "Ceiling".   SymUp         Rundet Stellen hinter dem Komma symmetrisch auf - also weg von der 0.                 Wirkt für positive Zahlen wie "AsymUp".                 Wirkt für negative Zahlen wie "AsymDown".   AsymArith     Asymmetrische arithmetische Rundung - rundet X,5 immer auf.                 Ähnelt der Java-Arbeitsblattfunktion "Round".   SymArith      Symmetrische arithmetische Rundung - rundet X,5 von 0 weg.                 Wirkt für positive Zahlen wie "AsymArith".                 Ähnelt der Excel-Arbeitsblattfunktion "Round".   BRound        Bankübliche Rundung.                 Rundet X,5 auf gerade Zahlen auf oder ab.                 Per Definitionem symmetrisch.   RandRound     Zufallsrundung.                 Rundet X,5 nach dem Zufallsprinzip entweder auf oder ab.   AltRound      Abwechselnde Rundung.                 Rundet X,5 abwechseln auf und ab.   ATruncDigits  Entspricht der Funktion "AsyncTrunc", verwendet jedoch andere Argumente.				

Alle genannten Funktionen arbeiten mit zwei Argumenten: mit der zu rundenden Zahl und einem optionalen Faktor. Wird dieser Faktor ausgelassen, ergeben die Funktionen eine ganze Zahl, die anhand der vorstehend beschriebenen Methoden ermittelt wird. Wird der Faktor angegeben, wird die Zahl um diesen Faktor skaliert, um verschiedene Rundungseffekte zu erzielen. So ergibt AsymArith(2.55, 10) zum Beispiel den Wert 2,6. Das heißt, dass wie folgt gerundet wird: 1/Faktor = 1/10 = 0,1.

Hinweis: Ein Faktor 0 führt zu einem Laufzeitfehler: 1/Faktor = 1/0.

Die folgende Tabelle zeigt die Auswirkungen diverser Faktoren:
   Ausdruck        Ergebnis   Erklärung   --------------------------------------------------------------------   AsymArith(2.5)     3       Rundet auf die nächste ganze Zahl auf.   BRound(2.18, 20)   2,2     Rundet auf die nächsten 5 Cents auf (1/20 Dollar).   SymDown(25, .1)    20      Rundet ab auf ein gerades Vielfaches von 10.				

Eine Ausnahme ist die Funktion "ADownDigits". Bei dieser vordefinierten Funktion können Sie statt des Faktors die Anzahl an Dezimalstellen angeben.
   Ausdruck        Ergebnis   Erklärung   ---------------------------------------------------------------------ADownDigits(2.18, 1)    2.1  Rundet ab auf das nächste Vielfache von 10 ^ -1.				

Auflistung der Funktionen


   Function AsymDown(ByVal X As Double, _            Optional ByVal Factor As Double = 1) As Double     AsymDown = Int(X * Factor) / Factor   End Function   Function SymDown(ByVal X As Double, _            Optional ByVal Factor As Double = 1) As Double     SymDown = Fix(X * Factor) / Factor   '  Alternately:   '  SymDown = AsymDown(Abs(X), Factor) * Sgn(X)   End Function   Function AsymUp(ByVal X As Double, _            Optional ByVal Factor As Double = 1) As Double   Dim Temp As Double     Temp = Int(X * Factor)     AsymUp = (Temp + IIf(X = Temp, 0, 1)) / Factor   End Function   Function SymUp(ByVal X As Double, _            Optional ByVal Factor As Double = 1) As Double   Dim Temp As Double     Temp = Fix(X * Factor)     SymUp = (Temp + IIf(X = Temp, 0, Sgn(X))) / Factor   End Function   Function AsymArith(ByVal X As Double, _            Optional ByVal Factor As Double = 1) As Double     AsymArith = Int(X * Factor + 0.5) / Factor   End Function   Function SymArith(ByVal X As Double, _            Optional ByVal Factor As Double = 1) As Double     SymArith = Fix(X * Factor + 0.5 * Sgn(X)) / Factor   '  Alternately:   '  SymArith = Abs(AsymArith(X, Factor)) * Sgn(X)   End Function   Function BRound(ByVal X As Double, _            Optional ByVal Factor As Double = 1) As Double   '  For smaller numbers:   '  BRound = CLng(X * Factor) / Factor   Dim Temp As Double, FixTemp As Double     Temp = X * Factor     FixTemp = Fix(Temp + 0.5 * Sgn(X))     ' Handle rounding of .5 in a special manner     If Temp - Int(Temp) = 0.5 Then       If FixTemp / 2 <> Int(FixTemp / 2) Then ' Is Temp odd         ' Reduce Magnitude by 1 to make even         FixTemp = FixTemp - Sgn(X)       End If     End If     BRound = FixTemp / Factor   End Function   Function RandRound(ByVal X As Double, _            Optional ByVal Factor As Double = 1) As Double   ' Should Execute Randomize statement somewhere prior to calling.   Dim Temp As Double, FixTemp As Double     Temp = X * Factor     FixTemp = Fix(Temp + 0.5 * Sgn(X))     ' Handle rounding of .5 in a special manner.     If Temp - Int(Temp) = 0.5 Then       ' Reduce Magnitude by 1 in half the cases.       FixTemp = FixTemp - Int(Rnd * 2) * Sgn(X)     End If     RandRound = FixTemp / Factor   End Function   Function AltRound(ByVal X As Double, _            Optional ByVal Factor As Double = 1) As Double   Static fReduce As Boolean   Dim Temp As Double, FixTemp As Double     Temp = X * Factor     FixTemp = Fix(Temp + 0.5 * Sgn(X))     ' Handle rounding of .5 in a special manner.     If Temp - Int(Temp) = 0.5 Then       ' Alternate between rounding .5 down (negative) and up (positive).       If (fReduce And Sgn(X) = 1) Or (Not fReduce And Sgn(X) = -1) Then       ' Or, replace the previous If statement with the following to       ' alternate between rounding .5 to reduce magnitude and increase       ' magnitude.       ' If fReduce Then         FixTemp = FixTemp - Sgn(X)       End If       fReduce = Not fReduce     End If     AltRound = FixTemp / Factor   End Function   Function ADownDigits(ByVal X As Double, _            Optional ByVal Digits As Integer = 0) As Double     ADownDigits = AsymDown(X, 10 ^ Digits)   End Function				

Hinweis: Mit Ausnahme der Excel-Arbeitsblattfunktion "MRound()" verwenden die integrierten Rundungsfunktionen Argumente in der Art von "ADownDigits", wobei das zweite Argument statt eines Faktors die Anzahl an Dezimalstellen angibt.

Bei den hier vorgestellten Rundungsverfahren wird ein Faktor verwendet, wie zum Beispiel "MRound()", der flexibler ist, weil keine Potenz von 10 gerundet werden muss. Sie können Wrapper-Funktionen mit "ADownDigits" erstellen.

Für die Gleitkommarechnung geltende Beschränkungen

Bei allen hier vorgestellten Rundungsverfahren wird der doppelte Datentyp verwendet, mit dem etwa 15 Dezimalstellen dargestellt werden können.

Da nicht alle Bruchwerte exakt dargestellt werden können, erhalten Sie möglicherweise unerwartete Ergebnisse, weil der angezeigte Wert nicht dem gespeicherten Wert entspricht.

So kann der Wert 2,25 intern zum Beispiel als 2,2499999... gespeichert werden, der bei der arithmetischen Rundung abgerundet werden würde, und nicht aufgerundet, wie Sie vielleicht erwarten. Je mehr Kalkulationen ein Wert durchläuft, desto größer ist die Wahrscheinlichkeit, dass der gespeicherte binäre Wert von dem exakten dezimalen Wert abweicht.

Wenn dies der Fall ist, sollten Sie vielleicht einen anderen Datentyp verwenden, wie zum Beispiel "Währung", der bis auf 4 Dezimalstellen exakt ist.

Außerdem könnten Sie den Datentyp "Variante" verwenden und mit "CDec()" arbeiten, um alle Werte in den Datentyp "Dezimal" zu konvertieren, der bis auf 28 Dezimalstellen genau sein kann.

Rundung von Währungswerten

Wenn Sie den Datentyp "Währung" verwenden, der bis auf 4 Dezimalstellen genau ist, möchten Sie in der Regel auf zwei Dezimalstellen runden, um zum Beispiel Cent darstellen zu können.

Die nachstehende Funktion "Round2CB" ist eine hartcodierte Variation der banküblichen Rundung, bei der zwar auf 2 Dezimalstellen gerundet, die ursprüngliche Zahl jedoch nicht multipliziert wird. Dadurch wird ein möglicher Überlauf verhindert, wenn sich der Währungsbetrag der Obergrenze für den Datentyp "Währung" nähert.
   Function Round2CB (ByVal X As Currency) As Currency     Round2CB = CCur(X / 100) * 100   End Function				

Runden dezimaler Werte

Nachstehend sehen Sie ein Beispiel für eine asymmetrische arithmetische Rundung unter Verwendung des Datentyps "Dezimal":
   Function AsymArithDec(ByVal X As Variant, _            Optional ByVal Factor As Variant = 1) As Variant     If Not IsNumeric(X) Then       AsymArithDec = X     Else       If Not IsNumeric(Factor) Then Factor = 1       AsymArithDec = Int(CDec(X * Factor) + .5)     End If   End Function				

Vernachlässigung der Präzision zwecks Abkürzung des Rundungsverfahrens

In der Schule lernt man bereits, dass Rundung in der Regel eine arithmetische Rundung unter Verwendung positiver Zahlen ist. Bei dieser Art der Rundung müssen Sie die genaue Zahl nur bis eine Stelle hinter der Stelle wissen, auf die gerundet wird. Die Stellen nach der ersten Dezimalstelle werden ignoriert. Um das Rundungsverfahren abzukürzen, wird also die Präzision etwas vernachlässigt.

So werden zum Beispiel sowohl 2,5 als auch 2,51 auf 3 aufgerundet, während 2,4 und 2,49 auf 2 abgerundet werden.

Wenn Sie die bankübliche Rundung verwenden (oder andere Verfahren, bei denen Werte wie 1,5 oder 2,5 mal auf- und mal abgerundet werden), oder wenn Sie die asymmetrische arithmetische Rundung auf negative Zahlen anwenden, kann eine Vernachlässigung der Präzision zu fehlerhaften Ergebnissen führen, bei denen nicht auf die nächstliegende Zahl gerundet wird.

Bei der banküblichen Rundung wird zum Beispiel 2,5 auf 2 abgerundet und 2,51 auf 3 aufgerundet.

Bei der asymmetrischen arithmetischen Rundung wird -2,5 auf -2 aufgerundet, während -2,51 auf -3 abgerundet wird.

Die in diesem Artikel vorgestellten benutzerdefinierten Funktionen berücksichtigen bei der Rundung die exakten Zahlen.
Verweise
Visual Basic-Hilfe, Version 6.0; Thema: Die Funktionen "Int", "Fix" und "Round"

Microsoft Transact SQL-Hilfe; Thema: Die Funktionen "Round", "Floor" und "Ceiling"

(c) Microsoft Corporation 1998, Alle Rechte vorbehalten. Beiträge von Malcolm Stewart, Microsoft Corporation.
Bitte beachten Sie: Bei diesem Artikel handelt es sich um eine Übersetzung aus dem Englischen. Es ist möglich, dass nachträgliche Änderungen bzw. Ergänzungen im englischen Originalartikel in dieser Übersetzung nicht berücksichtigt sind. Die in diesem Artikel enthaltenen Informationen basieren auf der/den englischsprachigen Produktversion(en). Die Richtigkeit dieser Informationen in Zusammenhang mit anderssprachigen Produktversionen wurde im Rahmen dieser Übersetzung nicht getestet. Microsoft stellt diese Informationen ohne Gewähr für Richtigkeit bzw. Funktionalität zur Verfügung und übernimmt auch keine Gewährleistung bezüglich der Vollständigkeit oder Richtigkeit der Übersetzung.
Eigenschaften

Artikelnummer: 196652 – Letzte Überarbeitung: 02/17/2006 17:39:28 – Revision: 3.2

  • Microsoft Visual Basic Control Creation Edition
  • Microsoft Visual Basic 5.0 Learning Edition
  • Microsoft Visual Basic 6.0 Learning Edition
  • Microsoft Visual Basic 5.0 Professional Edition
  • Microsoft Visual Basic 6.0 Professional Edition
  • Microsoft Visual Basic 5.0 Enterprise Edition
  • Microsoft Visual Basic 6.0 Enterprise Edition
  • Microsoft Visual Basic for Applications 5.0
  • Microsoft Visual Basic for Applications 6.0
  • Microsoft SQL Server 6.0 Standard Edition
  • Microsoft SQL Server 6.5 Standard Edition
  • Microsoft SQL Server 7.0 Standard Edition
  • kbhowto KB196652
Feedback