En java quand vous le faites
a % b
Si a est négatif, il renverra un résultat négatif, au lieu de revenir à b comme il se doit. Quelle est la meilleure façon de résoudre ce problème? La seule façon dont je peux penser est
a < 0 ? b + a : a % b
En java quand vous le faites
a % b
Si a est négatif, il renverra un résultat négatif, au lieu de revenir à b comme il se doit. Quelle est la meilleure façon de résoudre ce problème? La seule façon dont je peux penser est
a < 0 ? b + a : a % b
Réponses:
Il se comporte comme il se doit a% b = a - a / b * b; c'est à dire que c'est le reste.
Vous pouvez faire (a% b + b)% b
Cette expression fonctionne comme le résultat de (a % b)est nécessairement inférieur à b, peu importe si aest positif ou négatif. L'ajout bprend en charge les valeurs négatives de a, puisque (a % b)est une valeur négative entre -bet 0, (a % b + b)est nécessairement inférieure à bet positive. Le dernier modulo est là au cas où aétait positif au départ, car si aest positif (a % b + b)deviendrait plus grand que b. Par conséquent, le (a % b + b) % btransforme en plus petit que de bnouveau (et n'affecte pas les avaleurs négatives ).
(a % b)est nécessairement inférieur à b(peu importe s'il aest positif ou négatif), l'addition bprend en charge les valeurs négatives de a, car (a % b)est inférieur à bet inférieur à 0, (a % b + b)est nécessairement inférieur à bet positif. Le dernier modulo est là au cas où aétait positif au départ, car si aest positif (a % b + b)deviendrait plus grand que b. Par conséquent, le (a % b + b) % btransforme en plus petit que bnouveau (et n'affecte pas les avaleurs négatives ).
a < 0, peut-être que vous pourriez y jeter un coup d'œil)
(a % b + b) % bse décompose pour les très grandes valeurs de aet b. Par exemple, utiliser a = Integer.MAX_VALUE - 1et b = Integer.MAX_VALUEdonnera -3comme résultat, qui est un nombre négatif, ce que vous vouliez éviter.
whileserait plus lent si vous en avez vraiment besoin, sauf que vous n'avez besoin que d'un, ifauquel cas il est en fait plus rapide.
A partir de Java 8, vous pouvez utiliser Math.floorMod (int x, int y) et Math.floorMod (long x, long y) . Ces deux méthodes renvoient les mêmes résultats que la réponse de Peter.
Math.floorMod( 2, 3) = 2
Math.floorMod(-2, 3) = 1
Math.floorMod( 2, -3) = -1
Math.floorMod(-2, -3) = -2
floatou doublearguments. L'opérateur binaire Mod ( %) fonctionne également avec les opérandes floatet double.
Pour ceux qui n'utilisent pas (ou ne peuvent pas encore utiliser) Java 8, Guava est venu à la rescousse avec IntMath.mod () , disponible depuis Guava 11.0.
IntMath.mod( 2, 3) = 2
IntMath.mod(-2, 3) = 1
Une mise en garde: contrairement à Math.floorMod () de Java 8, le diviseur (le deuxième paramètre) ne peut pas être négatif.
En théorie des nombres, le résultat est toujours positif. Je suppose que ce n'est pas toujours le cas dans les langages informatiques car tous les programmeurs ne sont pas des mathématiciens. Mes deux cents, je considérerais cela comme un défaut de conception du langage, mais vous ne pouvez pas le changer maintenant.
= MOD (-4 180) = 176 = MOD (176, 180) = 176
car 180 * (-1) + 176 = -4 identique à 180 * 0 + 176 = 176
En utilisant l'exemple d'horloge ici, http://mathworld.wolfram.com/Congruence.html vous ne diriez pas que duration_of_time mod cycle_length est de -45 minutes, vous diriez 15 minutes, même si les deux réponses satisfont l'équation de base.
-1au lieu de, n-1par exemple) alors ayez à lui.
Java 8 a Math.floorMod, mais il est très lent (son implémentation a plusieurs divisions, multiplications et un conditionnel). Cependant, il est possible que la JVM dispose d'un stub intrinsèque optimisé, ce qui l'accélérerait considérablement.
Le moyen le plus rapide de faire cela sans floorModest comme d'autres réponses ici, mais sans branches conditionnelles et une seule opération lente %.
En supposant que n est positif et que x peut être n'importe quoi:
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;
Les résultats lorsque n = 3:
x | result
----------
-4| 2
-3| 0
-2| 1
-1| 2
0| 0
1| 1
2| 2
3| 0
4| 1
Si vous avez seulement besoin d 'une distribution uniforme entre 0et n-1et non l' opérateur de mod exact, et que vos xne se regroupent pas près 0, ce qui suit sera encore plus rapide, car il y a plus de parallélisme au niveau des instructions et le %calcul lent se produira en parallèle avec l 'autre pièces car elles ne dépendent pas de son résultat.
return ((x >> 31) & (n - 1)) + (x % n)
Les résultats pour ce qui précède avec 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
Si l'entrée est aléatoire dans la plage complète d'un entier, la distribution des deux solutions sera la même. Si les grappes d'entrée sont proches de zéro, il y aura trop peu de résultats n - 1dans cette dernière solution.
Voici une alternative:
a < 0 ? b-1 - (-a-1) % b : a % b
Cela pourrait ou non être plus rapide que cette autre formule [(a% b + b)% b]. Contrairement à l'autre formule, elle contient une branche, mais utilise une opération modulo en moins. Probablement une victoire si l'ordinateur peut prédire correctement un <0.
(Edit: Correction de la formule.)