[C#] Wie kann ich sicherstellen, dass eine Division von ganzen Zahlen immer aufgerundet wird?


Answers

Die endgültige int-basierte Antwort

Für vorzeichenbehaftete Ganzzahlen:

int div = a / b;
if (((a ^ b) >= 0) && (a % b != 0))
    div++;

Für vorzeichenlose Ganzzahlen:

int div = a / b;
if (a % b != 0)
    div++;

Die Begründung für diese Antwort

Ganzzahlige Division ' / ' ist definiert als Rundung auf Null (7.7.2 der Spezifikation), aber wir wollen aufrunden. Dies bedeutet, dass negative Antworten bereits richtig gerundet sind, aber positive Antworten müssen angepasst werden.

Nicht-Null-positive Antworten sind leicht zu erkennen, aber die Antwort Null ist ein wenig komplizierter, da dies entweder das Aufrunden eines negativen Wertes oder das Abrunden eines positiven Wertes sein kann.

Am sichersten ist es, zu erkennen, wann die Antwort positiv sein sollte, indem überprüft wird, ob die Vorzeichen beider Ganzzahlen identisch sind. Ganzzahliger xor-Operator ' ^ ' für die beiden Werte führt in diesem Fall zu einem 0-Zeichen-Bit, was ein nicht negatives Ergebnis bedeutet. Die Überprüfung (a ^ b) >= 0 legt also fest, dass das Ergebnis positiv sein sollte vor dem Runden. Beachten Sie auch, dass bei nicht vorzeichenbehafteten Ganzzahlen jede Antwort offensichtlich positiv ist. Daher kann diese Überprüfung weggelassen werden.

Die einzige verbleibende Überprüfung ist dann, ob eine Rundung stattgefunden hat, für die a % b != 0 die Aufgabe erledigt.

Gewonnene Erkenntnisse

Arithmetik (Ganzzahl oder anders) ist nicht annähernd so einfach wie es scheint. Sorgfältig gedacht, jederzeit erforderlich.

Auch wenn meine letzte Antwort vielleicht nicht so "einfach" oder "offensichtlich" oder vielleicht sogar "schnell" ist, wie der Fließkomma antwortet, hat sie eine sehr starke erlösende Qualität für mich; Ich habe jetzt die Antwort durchdacht , also bin ich mir eigentlich sicher, dass es richtig ist (bis jemand schlauer sagt mir etwas anderes - verstohlener Blick in Erics Richtung -).

Um das gleiche Gefühl der Gewissheit über die Fließkommaantwort zu bekommen, müsste ich mehr (und möglicherweise komplizierter) darüber nachdenken, ob es irgendwelche Bedingungen gibt, unter denen die Gleitkommapräzision in die Quere kommen könnte, und ob Math.Ceiling tut vielleicht etwas Unerwünschtes an "genau den richtigen" Eingaben.

Der Weg gereist

Ersetzen (ich habe das zweite myInt1 durch myInt2 , vorausgesetzt, das war das, was du myInt2 ):

(int)Math.Ceiling((double)myInt1 / myInt2)

mit:

(myInt1 - 1 + myInt2) / myInt2

Der einzige Nachteil ist, dass wenn myInt1 - 1 + myInt2 den von Ihnen verwendeten Integer-Typ überläuft, Sie möglicherweise nicht das bekommen, was Sie erwarten.

Grund ist das falsch : -1000000 und 3999 sollten -250 ergeben, das ergibt -249

BEARBEITEN:
Wenn man bedenkt, dass dies den gleichen Fehler wie die andere Ganzzahl-Lösung für negative myInt1 Werte hat, könnte es einfacher sein, myInt1 zu tun:

int rem;
int div = Math.DivRem(myInt1, myInt2, out rem);
if (rem > 0)
  div++;

Das sollte das richtige Ergebnis in div , das nur ganzzahlige Operationen verwendet.

Grund ist das falsch : -1 und -5 sollten 1 ergeben, das ergibt 0

EDIT (noch einmal, mit Gefühl):
Der Division Operator rundet auf Null ab; Bei negativen Ergebnissen ist dies genau richtig, so dass nur nicht-negative Ergebnisse angepasst werden müssen. DivRem bedenkt, dass DivRem nur ein / und ein % tut, lassen Sie uns den Aufruf überspringen (und beginnen Sie mit dem einfachen Vergleich, um die Modulo-Berechnung zu vermeiden, wenn sie nicht benötigt wird):

int div = myInt1 / myInt2;
if ((div >= 0) && (myInt1 % myInt2 != 0))
    div++;

Grund das ist falsch : -1 und 5 sollten 0 ergeben, das ergibt 1

(Zu meiner eigenen Verteidigung des letzten Versuchs hätte ich niemals eine vernünftige Antwort versuchen sollen, während mir mein Verstand sagte, dass ich 2 Stunden zu spät zum Schlafen gekommen war)

Question

Ich möchte sicherstellen, dass eine Division von ganzen Zahlen bei Bedarf immer aufgerundet wird. Gibt es einen besseren Weg als das? Es wird viel gegossen. :-)

(int)Math.Ceiling((double)myInt1 / myInt2)



Perfekte Chance, eine Erweiterungsmethode zu verwenden:

public static class Int32Methods
{
    public static int DivideByAndRoundUp(this int number, int divideBy)
    {                        
        return (int)Math.Ceiling((float)number / (float)divideBy);
    }
}

Dies macht Ihren Code auch lesbar:

int result = myInt.DivideByAndRoundUp(4);



Sie könnten etwas wie das Folgende verwenden.

a / b + ((Math.Sign(a) * Math.Sign(b) > 0) && (a % b != 0)) ? 1 : 0)



Links