Eingebauter .Net-Algorithmus zum Runden des Werts auf das nächste 10-Intervall

69

Wie kann man in C # einen Wert auf ein Intervall von 10 runden? Wenn ich zum Beispiel 11 habe, möchte ich, dass es 10 zurückgibt, wenn ich 136 habe, dann möchte ich, dass es 140 zurückgibt.

Ich kann es leicht von Hand machen

return ((int)(number / 10)) * 10;

Aber ich suche nach einem eingebauten Algorithmus, um diesen Job zu erledigen, so etwas wie Math.Round (). Der Grund, warum ich nicht von Hand machen möchte, ist, dass ich nicht überall in meinen Projekten den gleichen oder einen ähnlichen Code schreiben möchte, selbst für etwas so Einfaches wie das oben Genannte.

Graviton
quelle
6
Wenn es funktioniert, warum brauchen Sie etwas anderes? Wickeln Sie es einfach in eine Erweiterungsmethode oder eine gemeinsame Bibliothek ein und führen Sie es aus
John Sheehan
3
((Nummer + 5) / 10) * 10 - guter Grund, ein eingebautes zu finden. :-)
Adam Liss
2
Ich habe festgestellt, dass diese Frage verwirrt ist, und Sie sollten wahrscheinlich den Titel oder das Posting bearbeiten, um es klarer zu machen. Möchten Sie insbesondere immer aufrunden oder auf die nächsten 10 runden?
Raymond Martineau
2
Raymond, basierend auf dem tatsächlichen Inhalt der Frage und nicht auf dem Titel, ist es offensichtlich, dass es darum geht, auf die nächsten 10 zu runden. Aber ich habe auch diese Mehrdeutigkeit bemerkt und bin damit einverstanden, dass der Titel geändert werden sollte, um zu passen.
Chris Charabaruk
2
@Adam: Was ist falsch daran, eine einfache und unkomplizierte Codezeile in eine Methode zu verpacken? Sieht für mich nicht knifflig oder verwirrend aus.
Ed S.

Antworten:

104

In der Klassenbibliothek gibt es keine integrierte Funktion, die dies ausführt. Das nächstgelegene ist System.Math.Round (), das nur zum Runden von Zahlen der Typen Decimal und Double auf den nächsten ganzzahligen Wert dient. Wenn Sie mit .NET 3.5 arbeiten, können Sie Ihre Anweisung jedoch in eine Erweiterungsmethode einbinden, mit der Sie die Funktion viel sauberer verwenden können.

public static class ExtensionMethods
{
    public static int RoundOff (this int i)
    {
        return ((int)Math.Round(i / 10.0)) * 10;
    }
}

int roundedNumber = 236.RoundOff(); // returns 240
int roundedNumber2 = 11.RoundOff(); // returns 10

Wenn Sie mit einer älteren Version des .NET-Frameworks programmieren, entfernen Sie einfach das "this" aus der RoundOff-Funktion und rufen Sie die Funktion folgendermaßen auf:

int roundedNumber = ExtensionMethods.RoundOff(236); // returns 240
int roundedNumber2 = ExtensionMethods.RoundOff(11); // returns 10
Chris Charabaruk
quelle
1
Es gibt eine Reihe von Problemen mit diesem Code, nämlich, dass er nicht kompiliert wird (fehlender Rückgabetyp) und nicht auf den nächsten gerundet wird. In Ihrem Beispiel gibt es 230 und 10 zurück.
Dave Van den Eynde
1
Es wird immer noch nicht 240 zurückgeben, weil Sie abrunden.
Dave Van den Eynde
1
Führen Sie es tatsächlich aus. Hier ist die Quelle (einschließlich einer Testklasse) und sogar ein Build der Quelle. Es funktioniert und richtig. labs.coldacid.net/code/number-rounding-extension-method
Chris Charabaruk
3
Die Frage fragt nach "Aufrunden", aber diese Antwort rundet ab. Wenn Sie 11 eingeben, sollten Sie 20 zurückerhalten, nicht 10. Deshalb brauchen Sie Math.Ceiling().
Dan Diplo
4
Dan Diplo: Der nächste Satz, in dem OP erklärt, was er will, beschreibt die Abrundung. Lesen Sie die ganze Frage, nicht nur den ersten Satz.
Chris Charabaruk
23

Verwenden Sie Math.Ceiling, um immer aufzurunden.

int number = 236;
number = (int)(Math.Ceiling(number / 10.0d) * 10);

Der Modul (%) erhält den Rest, sodass Sie Folgendes erhalten:

// number = 236 + 10 - 6

Fügen Sie das in eine Erweiterungsmethode ein

public static int roundupbyten(this int i){
    // return i + (10 - i % 10); <-- logic error. Oops!
    return (int)(Math.Ceiling(i / 10.0d)*10); // fixed
}

// call like so:
int number = 236.roundupbyten();

oben bearbeitet: Ich hätte mit meinem ersten Instinkt Math.Ceiling verwenden sollen

Ich habe darüber gebloggt, als ich UPC-Prüfziffern berechnet habe .

Armstrongest
quelle
2
Versuchen Sie es mit 240. Was bekommen Sie dann? Oder für diese Angelegenheit, 11.
Chris Charabaruk
12

Das könnte etwas zu spät sein, aber ich denke, das könnte eines Tages eine gute Hilfe sein ...

Ich habe das versucht:

public int RoundOff(int number, int interval){
    int remainder = number % interval;
    number += (remainder < interval / 2) ? -remainder : (interval - remainder);
    return number;
}

Benutzen:

int number = 11;
int roundednumber = RoundOff(number, 10);

Auf diese Weise haben Sie die Wahl, ob die Hälfte des Intervalls aufgerundet oder abgerundet werden soll. =)

Jronny
quelle
5

Das Runden eines Gleitkommas auf eine Ganzzahl ähnelt (int) (x + 0,5), im Gegensatz zum einfachen Umwandeln von x - wenn Sie ein Vielfaches von 10 möchten, können Sie dies leicht anpassen.

Wenn Sie nur ganzzahlige Berechnungen durchführen möchten und diese auf zehn runden möchten, versuchen Sie (x + 10/2) / 10 * 10.

Bearbeiten: Ich habe festgestellt, dass diese Antwort nicht der Anfrage des Autors des Originals entspricht und auch eine voreingenommene Form der Rundung ist, die ich lieber nicht mache. In einer anderen akzeptierten Antwort wurde jedoch bereits Math.round () angegeben, eine viel bessere Lösung.

Raymond Martineau
quelle
1
Ich muss sagen, dass Math.Round viel sauberer aussieht, obwohl dies der Trick ist, den ich in der Vergangenheit oft verwendet habe.
Dave Van den Eynde
2

Alte Frage, aber hier ist eine Möglichkeit, das zu tun, was gestellt wurde, und ich habe sie erweitert, um eine beliebige Anzahl auf die Anzahl der gewünschten Sig-Feigen runden zu können.

    private double Rounding(double d, int digits)
    {
        int neg = 1;
        if (d < 0)
        {
            d = d * (-1);
            neg = -1;
        }

        int n = 0;
        if (d > 1)
        {
            while (d > 1)
            {
                d = d / 10;
                n++;
            }
            d = Math.Round(d * Math.Pow(10, digits));
            d = d * Math.Pow(10, n - digits);
        }
        else
        {
            while (d < 0.1)
            {
                d = d * 10;
                n++;
            }
            d = Math.Round(d * Math.Pow(10, digits));
            d = d / Math.Pow(10, n + digits);
        }

        return d*neg;
    }


   private void testing()
   {
       double a = Rounding(1230435.34553,3);
       double b = Rounding(0.004567023523,4);
       double c = Rounding(-89032.5325,2);
       double d = Rounding(-0.123409,4);
       double e = Rounding(0.503522,1);
       Console.Write(a.ToString() + "\n" + b.ToString() + "\n" + 
           c.ToString() + "\n" + d.ToString() + "\n" + e.ToString() + "\n");
   }
Lucas925
quelle
2

Ich ziehe es vor, weder die MathBibliothek einzubringen noch zum Gleitkomma zu gehen, daher ist mein Vorschlag, nur eine ganzzahlige Arithmetik wie unten durchzuführen, wo ich auf die nächsten 1K aufrunde. Wickeln Sie es in eine Methode oder ein Lambda-Snippet oder etwas anderes, wenn Sie es nicht wiederholen möchten.

int MyRoundedUp1024Int = ((lSomeInteger + 1023) / 1024) * 1024;

Ich habe keine Leistungstests für diese oder andere Methoden durchgeführt, aber ich wette, es ist der schnellste Weg, dies zu tun, außer vielleicht eine Verschiebung und Rotation der Bit-Version davon.

Dave
quelle