In Java, wenn Sie dies tun
a % b
Wenn a negativ ist, wird ein negatives Ergebnis zurückgegeben, anstatt wie gewünscht um b zu wickeln. Was ist der beste Weg, um dies zu beheben? Ich kann nur denken
a < 0 ? b + a : a % b
In Java, wenn Sie dies tun
a % b
Wenn a negativ ist, wird ein negatives Ergebnis zurückgegeben, anstatt wie gewünscht um b zu wickeln. Was ist der beste Weg, um dies zu beheben? Ich kann nur denken
a < 0 ? b + a : a % b
Antworten:
Es verhält sich wie es sollte a% b = a - a / b * b; dh es ist der Rest.
Sie können (a% b + b)% b ausführen
Dieser Ausdruck funktioniert als Ergebnis von (a % b)
ist notwendigerweise niedriger als b
, egal ob a
positiv oder negativ. Hinzufügen b
kümmert sich um die negativen Werte a
, da (a % b)
zwischen ein negativer Wert ist -b
und 0
, (a % b + b)
ist notwendigerweise niedriger als b
und positiv. Das letzte Modulo ist a
da, falls a
es anfangs positiv war, denn wenn es positiv ist, (a % b + b)
würde es größer werden als b
. Daher wird (a % b + b) % b
es kleiner als b
wieder (und wirkt sich nicht auf negative a
Werte aus).
(a % b)
notwendigerweise niedriger ist als b
(egal ob a
positiv oder negativ), das Addieren b
berücksichtigt die negativen Werte von a
, da (a % b)
niedriger als b
und niedriger als 0
, (a % b + b)
notwendigerweise niedriger als b
und positiv ist. Das letzte Modulo ist a
da, falls a
es anfangs positiv war, denn wenn es positiv ist, (a % b + b)
würde es größer werden als b
. Daher wird (a % b + b) % b
es kleiner als b
wieder (und wirkt sich nicht auf negative a
Werte aus).
a < 0
, vielleicht könnten Sie einen Blick darauf werfen)
(a % b + b) % b
für sehr große Werte von a
und zusammenbricht b
. Wenn Sie beispielsweise a = Integer.MAX_VALUE - 1
und verwenden b = Integer.MAX_VALUE
, erhalten Sie -3
als Ergebnis eine negative Zahl, die Sie vermeiden möchten.
while
wäre langsamer, wenn Sie es wirklich brauchen, außer Sie brauchen nur ein. if
In diesem Fall ist es tatsächlich schneller.
Ab Java 8 können Sie Math.floorMod (int x, int y) und Math.floorMod (long x, long y) verwenden . Beide Methoden liefern die gleichen Ergebnisse wie Peters Antwort.
Math.floorMod( 2, 3) = 2
Math.floorMod(-2, 3) = 1
Math.floorMod( 2, -3) = -1
Math.floorMod(-2, -3) = -2
float
oder double
Argumenten. Mod binärer Operator ( %
) funktioniert auch mit float
und double
Operanden.
Für diejenigen, die Java 8 noch nicht verwenden (oder noch nicht verwenden können), kam Guava mit IntMath.mod () , das seit Guava 11.0 verfügbar ist , zur Rettung .
IntMath.mod( 2, 3) = 2
IntMath.mod(-2, 3) = 1
Eine Einschränkung: Im Gegensatz zu Math.floorMod () von Java 8 kann der Divisor (der zweite Parameter) nicht negativ sein.
In der Zahlentheorie ist das Ergebnis immer positiv. Ich würde vermuten, dass dies in Computersprachen nicht immer der Fall ist, da nicht alle Programmierer Mathematiker sind. Meine zwei Cent, ich würde es als Designfehler der Sprache betrachten, aber Sie können es jetzt nicht ändern.
= MOD (-4.180) = 176 = MOD (176, 180) = 176
weil 180 * (-1) + 176 = -4 das gleiche wie 180 * 0 + 176 = 176
Anhand des Uhrbeispiels hier, http://mathworld.wolfram.com/Congruence.html , würden Sie nicht sagen, dass die Dauer_der_Zeitmod-Zykluslänge -45 Minuten beträgt, sondern 15 Minuten, obwohl beide Antworten die Basisgleichung erfüllen.
-1
statt n-1
zum Beispiel). dann hab es drauf.
Java 8 hat Math.floorMod
, aber es ist sehr langsam (seine Implementierung hat mehrere Unterteilungen, Multiplikationen und eine Bedingung). Es ist jedoch möglich, dass die JVM über einen intrinsisch optimierten Stub verfügt, der sie erheblich beschleunigen würde.
Der schnellste Weg, dies ohne zu tun, floorMod
ist wie einige andere Antworten hier, aber ohne bedingte Verzweigungen und nur eine langsame %
Operation.
Angenommen, n ist positiv und x kann alles sein:
int remainder = (x % n); // may be negative if x is negative
//if remainder is negative, adds n, otherwise adds 0
return ((remainder >> 31) & n) + remainder;
Die Ergebnisse, wenn n = 3
:
x | result
----------
-4| 2
-3| 0
-2| 1
-1| 2
0| 0
1| 1
2| 2
3| 0
4| 1
Wenn Sie nur eine gleichmäßige Verteilung zwischen 0
und n-1
nicht dem exakten Mod-Operator benötigen und Ihre x
nicht in der Nähe gruppieren 0
, ist das Folgende noch schneller, da mehr Parallelität auf Befehlsebene besteht und die langsame %
Berechnung parallel zum anderen erfolgt Teile, da sie nicht vom Ergebnis abhängen.
return ((x >> 31) & (n - 1)) + (x % n)
Die Ergebnisse für die oben genannten mit n = 3
:
x | result
----------
-5| 0
-4| 1
-3| 2
-2| 0
-1| 1
0| 0
1| 1
2| 2
3| 0
4| 1
5| 2
Wenn die Eingabe im gesamten Bereich eines int zufällig ist, ist die Verteilung beider beiden Lösungen gleich. Wenn sich die Eingangscluster nahe Null befinden, gibt es bei n - 1
der letzteren Lösung zu wenige Ergebnisse .
Hier ist eine Alternative:
a < 0 ? b-1 - (-a-1) % b : a % b
Dies kann schneller sein oder auch nicht als die andere Formel [(a% b + b)% b]. Im Gegensatz zur anderen Formel enthält sie einen Zweig, verwendet jedoch eine Modulo-Operation weniger. Wahrscheinlich ein Gewinn, wenn der Computer eine <0 richtig vorhersagen kann.
(Bearbeiten: Die Formel wurde korrigiert.)