Feedback

Kaufmännisches Runden in Decimal

Sprache: C#

In .NET 1.1 ist, wie in einigen anderen Sprachen auch, das Runden mit Math.Round auf Grund von möglichen Verzerrungen bei Statistiken (siehe Wikipedia, siehe IEEE 754), nicht für ein kaufmännisches Runden geeignet. Aus 3,65 wird (bei Runden auf eine Ziffer) 3,6 da zur nächsten geraden Stelle gerundet wird. Diese statische Methode umgeht diese Besonderheit und ermöglicht ein kaufmännisches Runden.
/// <summary>
/// Rundet kaufmännisch auf die Anzahl der übergebenen Nachkommastellen
///
/// Achtung: Seit .NET 2.0 gibt es folgende Überladung die dieses Snippet hinfällig machen: Math.Round(3.65m,1,MidpointRounding.AwayFromZero)
/// </summary>
/// <param name="value">Zu rundender Wert</param>
/// <param name="dec">Anzahl der Nachkommastellen</param>
/// <returns>Gerundeter Wert</returns>
public static decimal CommercialRound(decimal value, int dec)
{
	// um die Anzahl der Dezimalstellen nach links verschieben
	decimal x = value * Convert.ToDecimal(Math.Pow(10, dec));

	// Dezimalstellen abtrennen
	decimal y = Math.Floor(x);

	// ist die Differenz größer oder gleich 0.5 soll aufgerundet werden
	if ((x-y) >= 0.5m) y++;

	// um die Anzahl der Dezimalstellen nach rechts verschieben 
	return y / Convert.ToDecimal(Math.Pow(10, dec));
}
/// <summary>
/// Rundet kaufmännisch auf die Anzahl der übergebenen Nachkommastellen
///
/// Achtung: Seit .NET 2.0 gibt es folgende Überladung die dieses Snippet hinfällig machen: Math.Round(3.65m,1,MidpointRounding.AwayFromZero)
/// </summary>
/// <param name="value">Zu rundender Wert</param>
/// <param name="dec">Anzahl der Nachkommastellen</param>
/// <returns>Gerundeter Wert</returns>
public static decimal CommercialRound(decimal value, int dec)
{
	// um die Anzahl der Dezimalstellen nach links verschieben
	decimal x = value * Convert.ToDecimal(Math.Pow(10, dec));

	// Dezimalstellen abtrennen
	decimal y = Math.Floor(x);

	// ist die Differenz größer oder gleich 0.5 soll aufgerundet werden
	if ((x-y) >= 0.5m) y++;

	// um die Anzahl der Dezimalstellen nach rechts verschieben 
	return y / Convert.ToDecimal(Math.Pow(10, dec));
}

4 Kommentare

  1. komisch bei mir macht er das richtig
    [code]3,6 = Math.Round(Convert.ToDecimal(„3,64“),1,MidpointRounding.AwayFromZero));
    3,7 = Math.Round(Convert.ToDecimal(„3,65“),1,MidpointRounding.AwayFromZero));[/code]

  2. Ja, BlackDragon… da hast du in der Tat recht. Diese Überladung ist seit dem Framework 2.0 neu hinzugekommen. Insofern ist mein Snippet nur für .NET 1.1 zu empfehlen. Wieder etwas gelernt, danke für den Hinweis ;o).

  3. Der Code funktioniert für negative Zahlen nicht zuverlässig.
    So liefert bspw. CommercialRound(-1.55m, 1) als Ergebnis -1.5 und nicht -1.6!
    Oder ist das Absicht?

    Hier meine Implementierung:

    [code]
    public static decimal RoundNumber( decimal number, int decimals )
    {
    if ( decimals < 0 || decimals > 8 )
    throw new ArgumentOutOfRangeException( „decimals must be between 0 and 8“, „decimals“ );

    //Komma verschieben
    int shiftFactor = (int)Math.Pow( 10, decimals );
    decimal tmp = number * shiftFactor;

    //Runden: 0.5 addieren/subtrahieren und dann Nachkommastellen abschneiden
    decimal diff = ( tmp >= 0 ? 0.5m : -0.5m );
    tmp = (long)( tmp + diff );

    //Komma wieder verschieben
    return ( tmp / shiftFactor );
    }
    [/code]