Feedback

C# - Kaufmännisches Runden in Decimal

Veröffentlicht von am 11/6/2006
(4 Bewertungen)
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));
}
Abgelegt unter Round, kaufmännisch, Runden, Decimal, C#, Snippet.

4 Kommentare zum Snippet

BlackDragon schrieb am 11/7/2006:
komisch bei mir macht er das richtig
3,6 = Math.Round(Convert.ToDecimal("3,64"),1,MidpointRounding.AwayFromZero));
3,7 = Math.Round(Convert.ToDecimal("3,65"),1,MidpointRounding.AwayFromZero));
Yellow schrieb am 11/7/2006:
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).
Marvin schrieb am 2/10/2007:
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:


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 );
}
Yellow schrieb am 2/14/2007:
Hallo Marvin,

danke für den Hinweis. Du hast natürlich recht. Die kaufmännische Rundung muss bei negativen Zahlen abrundnen...
 

Logge dich ein, um hier zu kommentieren!