Guten Abend,
ich weiß, zu dem Thema gibt es bereits viele Einträge und ich habe auch bereits viel probiert. Leider kommt ich aber nicht auf mein gewünschtes Ergebnis.
Preis: 6,30
Rabatt: 10%
Abschlag: 0,63
Ergebnis: 5,67
Im ersten Beispiel runde ich auf 0,25, ergibt dann 5,75, was passt.
Im zweiten Beispiel runde ich auf 0,5, da erhalte ich immer 5,5. Warum wird hier nicht aufgerundet auf 5,7?
public static decimal RabattiertenPreisBerechnen(decimal preis, decimal rabatt)
{
decimal abschlag = Math.Round(preis * (rabatt / 100), 2, MidpointRounding.ToEven);
decimal rabattpreis = preis - abschlag;
// Um auf 0,25 zu runden, funktioniert folgende Zeile zu meinem Beispiel = 5,75.
//rabattpreis = Math.Round(rabattpreis * 4, MidpointRounding.ToEven) / 4;
// Um auf 0,5 zu runden => erhalte ich in beiden Fällen 5,5.
rabattpreis = Math.Round(rabattpreis * 2, MidpointRounding.ToEven) / 2;
//rabattpreis = Math.Round(rabattpreis * 2, MidpointRounding.AwayFromZero) / 2;
//rabattpreis = Math.Round(rabattpreis, MidpointRounding.AwayFromZero); => 5,67
//rabattpreis = Math.Round(rabattpreis, MidpointRounding.ToEven); => 6
return rabattpreis;
}
Das Problem hier ist nicht das Kaufmännische Runden, sondern Deine Logik. Kaufmännische Runden erfolgt, wenn man alles berechnet hat - am Ende.
Das machst Du aber leider nicht.
In Deinem Code rundest Du, und teilst danach durch 2.
Math.Round(rabattpreis * 2, MidpointRounding.AwayFromZero) / 2
Die Rundungsoptionen wirken sich also nicht aus.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Macht's einen Unterschied, wenn du durch
100m
anstatt durch
100
teilst ?
(Und analog dazu die Multiplikation / Division mit 2: aus 2 mach 2m )
"m" ist ein guter Hinweis, sollte hier verwendet werden.
Da es jedoch ein Logikfehler ist - nicht Syntax - ändert das leider am Ergebnis nichts.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Kaufmännische Runden erfolgt, wenn man alles berechnet hat - am Ende.
Es wird nach jedem Zwischenschritt der ein Ergebnis ausgibt gerundet.
Sonst könnte man die Rechenschritte nicht nachvollziehen.
Grüße Bernd
Workshop : Datenbanken mit ADO.NET
Xamarin Mobile App : Finderwille Einsatz App
Unternehmenssoftware : Quasar-3
Würde meine Hand dafür nicht ins Feuer legen, aber eine kurze Google Recherche sagt eigentlich auch, dass die Zwischenschritte i.d.R. nicht gerundet werden.
Es gibt aber wohl weder nach DIN 1333 noch nach Gesetzeslage eine feste Regel.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Es wird nach jedem Zwischenschritt der ein Ergebnis ausgibt gerundet.
Wenn du nach jedem Zwischenschritt rundest könnten Rundungsfehler entstehen, was das Endergebnis verfälschen könnte. Von daher würde ich tatsächlich auch erst am Ende das Ergebnis runden.
Danke mal für Eure Tipps! Habe versucht alles entsprechend umzusetzen (100 durch 100m ersetzt, keine Rundun beim Abschlag bzw. erst am Ende runden) - dennoch erhalte ich nicht das, was ich gerne möchte.
public static decimal RabattiertenPreisBerechnen(decimal preis, decimal rabatt)
{
decimal abschlag = preis * (rabatt / 100m);
decimal rabattpreis = preis - abschlag;
decimal d;
//d = Math.Round(rabattpreis, 2, MidpointRounding.AwayFromZero); =>5,67
d = Math.Round(rabattpreis, 2, MidpointRounding.ToEven); =5,67
return d;
}
Den erhofften Wert von 5,7 erhalte ich nur, wenn ich
d = Math.Round(rabattpreis, 1, MidpointRounding.ToEven); =5,67
mit einer Dezimalstelle zurückgebe.
Muss ich das in der Tat so machen, oder runde ich weiter falsch?
Zumindestens bei Rechnungen gibt es in Deutschland genaue Vorschriften, und da muss nach jeden Zwischenschritt, der ausgegeben wird, gerundet werden.
Sonst erfüllt man die nicht Vorgaben für Rechnungen gemäß Umsatzsteuergesetz und den Grundsätzen der ordnungsgemäßen Buchführung.
Grüße Bernd
Workshop : Datenbanken mit ADO.NET
Xamarin Mobile App : Finderwille Einsatz App
Unternehmenssoftware : Quasar-3
mit einer Dezimalstelle zurückgebe.
Muss ich das in der Tat so machen, oder runde ich weiter falsch?
Ich glaube Du vermischt da gerade zwei Theman.
Es ist ja völlig okay, dass nun 5.7 raus kommt - das ist für decimal ein legitimer Wert. Es ist auch üblich dass hier keine weiteren 0-stellen "zu sehen sind".
Wenn es Dir dann um eine Ausgabe geht, dann gibt es string.Format dafür. Das eine ist also der interne Wert, das andere ist der darzustellende Wert.
Console.WriteLine(Math.Round(rabattpreis, 1, MidpointRounding.AwayFromZero)); // 5.7
Console.WriteLine(Math.Round(rabattpreis, 1, MidpointRounding.AwayFromZero).ToString("0.00")); // 5.70
Die Standard-Ausgabe der Darstellung ist halt nicht so formatiert, als dass es ein Preis wäre, denn nicht jeder Decimal-Wert ist halt auch ein Preis.
Zumindestens bei Rechnungen gibt es in Deutschland genaue Vorschriften, und da muss nach jeden Zwischenschritt, der ausgegeben wird, gerundet werden.
Das ist so formuliert vermutlich nicht korrekt.
Natürlich muss Deine Bilanzierung korrekt sein - der Weg dahin ist gesetzlich nicht geregelt. Das Kaufmännische Runden kann jedoch ein Hilfsmittel dazu sein.
Dank der Vertragsfreiheit bist Du aber selbst der Entscheider, die Du auf Deine Preise kommst. Entscheidend ist, dass die Bilanz und die Rechnung korrekt ist.
Rundungsfehler sind davon abgesehen niemals vermeidbar, auch nicht mit Kaufmännischem Runden (vor allem bei der Berechnung von Steuern).
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Hast du dir die Hinweise zu den möglichen Rundungsfehlern schonmal angeschaut?
https://learn.microsoft.com/en-us/dotnet/api/system.math.round?view=net-6.0#midpoint-values-and-rounding-conventions (Docs)
Rounding away from zero is the most widely known form of rounding, while rounding to nearest even is the standard in financial and statistical operations. It conforms to IEEE Standard 754, section 4.
ToEven entspricht dem banker's rounding, was spricht denn gegen deine Zeile
d = Math.Round(rabattpreis, 1, MidpointRounding.ToEven);
?
Wenn man 5,70 anstatt 5,7 ausgibt, dann würde ich das nicht als Rundung von 5,67 interpretieren sondern als Rundung von bspw. 5,701 bis 5,704 auf 5,70. Aus diesem Grund sind die beiden Nachkommastellen aus meiner Sicht auch eher irreführend als hilfreich.