Feedback

C# - Alternatives Runden

Veröffentlicht von am 16.10.2015
(0 Bewertungen)
Mit dieser Funktion können double-Werte mit einer anderen Schrittgröße gerundet werden.
Normalerweise beträgt die Schrittgröße beim Runden 1, also es wird auf 0 und 1 gerundet.
Zahl ist die zu rundende Zahl
Stelle gibt an, auf welche Stelle hinter (>=1) oder vor (<=0) dem Komma gerundet werden soll.
step ist die Schrittgröße, dessen Kehrwert ganzzahlig sein muss.
Mit mode wird angegeben, ob im Zweifelsfall, also wenn eine Zahl sich genau zwischen den beiden möglichen Rundungszielen befindet, auf- oder abgerundet werden soll. Dieser Parameter ist optional und würde bei Nichtangabe zum Aufrunden im Zweifelsfall führen.
Beispiel: Zahl = 9.76, Stelle = 1, step = 0.5
Hier ist die Schrittgröße 0.5, also wird auf 0, 0.5 und 1 gerundet
Das Ergebnis wäre 9.75

Beispiel für Zweifelsfall:
Zahl = 0.25, Stelle = 0, step = 0.5
Die Zahl befindet sich genau zwischen den möglichen Rundungszielen von 0 und 0.5.
Wird AwayFromZero als mode angeben, wird auf 0.5 aufgerundet.
Ist mode aber ToEven, wird auf 0 abgerundet.

public static double RoundTo(double Zahl, int Stelle, double step, MidpointRounding mode = MidpointRounding.AwayFromZero)
        {
            double Out = 0;
            if (Convert.ToInt32(1 / step) == (1 / step) && step > 0)
            {
                double Up = Math.Abs(Zahl) * Math.Pow(10, Stelle);
                double temp = Up;
                Up = Up % step;
                if (Up < step / 2 || (Up == step / 2 && mode == MidpointRounding.ToEven))
                { Out = temp - Up; }//Abrunden
                else if (Up > step / 2 || Up == step / 2 && mode == MidpointRounding.AwayFromZero)
                { Out = temp - Up + step; }//Aufrunden
                if (Zahl < 0)
                { Out *= -1; }
                Out /= Math.Pow(10, Stelle);
            }
            else
            { throw new ArgumentException("Keine gültige Schrittgröße angegeben. Der Wert muss zwischen 0 und 1 liegen und der Kehrwert eine natürliche Zahl ergeben"); }
            return Out;
        }
Abgelegt unter double, Runden.

6 Kommentare zum Snippet

Martin Dauskardt schrieb am 17.10.2015:
Was spricht denn gegen
Math.Round(decimal, Stellen, MidpointRounding.ToEven);
?
Koopakiller schrieb am 18.10.2015:
@Martin
Die Methode hat soweit ich sehe 2 Vorteile:
1. Sie kann auch vor dem Komma runden, also beispielsweise auf 10, 20, 30, ...
2. Die Methode kann auch in nicht 10er Schritten runden, also beispielsweise auf 0.5

@Fuzzi59
Du solltest noch eine ordentliche Validierung der Eingabeparameter einbauen. Speziell meine ich das werfen einer speziellen Exception, nicht dem Basistyp.
Was ich noch nett finden würde wäre ein 4. Parameter der angibt ob im Zweifelsfall auf- oder abgerundet werden soll. Auch könnte man bestimmen ob immer auf- oder immer abgerundet wird.
Und gucke mal ob du den Modulo-Operator % statt der While-Schleife einbauen kannst. Das kann einiges an Leistung einsparen.
Fuzzi59 schrieb am 19.10.2015:
Ich hab jetzt den Modulo-Operator eingebaut. Allerdings verstehe ich nicht was mit Zweifelsfall gemeint sein soll. Wenn die Zahl im Beispiel jetzt 9.75 wäre, würde die Funktion auf 10 aufrunden, genau so, als wenn man bei 9.5 auf 10 aufrundet, wenn man die übliche Math.Round-Methode anwenden würde.
Koopakiller schrieb am 19.10.2015:
Mit Zweifelsfall meine Ich folgendes:
Es soll in 0.5er Schritten gerundet werden. Wenn nun mein Double 0.25 ist, wird dann auf 0 oder 0.5 gerundet? Die Math.Round-Methode nimmt einen Enumerationswert dafür entgegen. Wenn keiner angegeben wird, wird aufgerundet. Es gibt aber viele verschiedene Wege den Wert zu runden:
- immer abrunden
- immer aufrunden
- immer passend runden, im Zweifelsfall auf
- immer passend runden, im Zweifelsfall ab


Übrigens, ArgumentException oder ArgumentOutOfRangeException sind besser als Exception.
Fuzzi59 schrieb am 20.10.2015:
Ich habe die Funktion noch um den Parameter mode erweitert, womit man angeben kann, wie im Zweifelsfall gerundet werden soll. Grundsätzlich wird im Zweifelsfall aufgerundet, wenn man den mode-Parameter nicht übergibt.
Koopakiller schrieb am 20.10.2015:
Jetzt gefällt mir dein Snippet schon richtig gut 👍

Mir fiel gerade noch ein kleines Problem auf. Angenommen du willst auf 1/49 runden (wer auch immer das tun will). Dann hast du das typische Problem von Gleitkommazahlen:
1D / (1D / 49D) = 49.000000000000007

Daher wird bei folgendem Aufruf die ArgumentException geworfen.
RoundTo(1, 1, 1 / 49D);

Ändern könnte man das indem man einen Integer entgegen nimmt aus dem du dann 1/x errechnest. So könntest du auch die Fehlerüberprüfung auf Werte <=0 vereinfachen.
 

Logge dich ein, um hier zu kommentieren!