En java cuando lo hagas
a % b
Si a es negativo, devolverá un resultado negativo, en lugar de ajustarse a b como debería. ¿Cuál es la mejor forma de solucionar este problema? La única forma en que puedo pensar es
a < 0 ? b + a : a % b
En java cuando lo hagas
a % b
Si a es negativo, devolverá un resultado negativo, en lugar de ajustarse a b como debería. ¿Cuál es la mejor forma de solucionar este problema? La única forma en que puedo pensar es
a < 0 ? b + a : a % b
Respuestas:
Se comporta como debería a% b = a - a / b * b; es decir, es el resto.
Puedes hacer (a% b + b)% b
Esta expresión funciona porque (a % b)
es necesariamente menor que b
, sin importar si a
es positivo o negativo. La suma b
se ocupa de los valores negativos de a
, ya que (a % b)
es un valor negativo entre -b
y 0
, (a % b + b)
es necesariamente menor que b
y positivo. El último módulo está ahí en caso de que a
fuera positivo al principio, ya que si a
es positivo (a % b + b)
se volvería más grande que b
. Por lo tanto, lo (a % b + b) % b
convierte en más pequeño que b
nuevamente (y no afecta los a
valores negativos ).
(a % b)
es necesariamente menor que b
(no importa si a
es positivo o negativo), la suma b
se encarga de los valores negativos de a
, ya que (a % b)
es menor que b
y menor que 0
, (a % b + b)
es necesariamente menor que b
y positivo. El último módulo está ahí en caso de que a
fuera positivo para empezar, ya que si a
es positivo (a % b + b)
se volvería más grande que b
. Por lo tanto, lo (a % b + b) % b
convierte en más pequeño que b
nuevamente (y no afecta los a
valores negativos ).
a < 0
, tal vez podría echar un vistazo)
(a % b + b) % b
se desglosa para valores muy grandes de a
y b
. Por ejemplo, usar a = Integer.MAX_VALUE - 1
y b = Integer.MAX_VALUE
dará -3
como resultado, que es un número negativo, que es lo que quería evitar.
while
sería más lento si realmente lo necesita, excepto que solo necesita un, if
en cuyo caso es más rápido.
A partir de Java 8, puede usar Math.floorMod (int x, int y) y Math.floorMod (long x, long y) . Ambos métodos arrojan los mismos resultados que la respuesta de Peter.
Math.floorMod( 2, 3) = 2
Math.floorMod(-2, 3) = 1
Math.floorMod( 2, -3) = -1
Math.floorMod(-2, -3) = -2
float
o double
argumentos. El operador binario Mod ( %
) también funciona con operandos float
y double
.
Para aquellos que aún no usan (o no pueden usar) Java 8, Guava vino al rescate con IntMath.mod () , disponible desde Guava 11.0.
IntMath.mod( 2, 3) = 2
IntMath.mod(-2, 3) = 1
Una advertencia: a diferencia de Math.floorMod () de Java 8, el divisor (el segundo parámetro) no puede ser negativo.
En teoría de números, el resultado siempre es positivo. Supongo que este no es siempre el caso en los lenguajes informáticos porque no todos los programadores son matemáticos. Mis dos centavos, lo consideraría un defecto de diseño del lenguaje, pero no puedes cambiarlo ahora.
= MOD (-4,180) = 176 = MOD (176, 180) = 176
porque 180 * (-1) + 176 = -4 lo mismo que 180 * 0 + 176 = 176
Usando el ejemplo del reloj aquí, http://mathworld.wolfram.com/Congruence.html , no diría que duration_of_time mod cycle_length es -45 minutos, diría que 15 minutos, aunque ambas respuestas satisfacen la ecuación base.
-1
lugar de, n-1
por ejemplo) entonces hágalo.
Java 8 tiene Math.floorMod
, pero es muy lento (su implementación tiene múltiples divisiones, multiplicaciones y un condicional). Sin embargo, es posible que la JVM tenga un código auxiliar optimizado intrínseco, lo que lo aceleraría significativamente.
La forma más rápida de hacer esto sin floorMod
es como algunas otras respuestas aquí, pero sin ramas condicionales y solo una %
operación lenta .
Suponiendo que n es positivo y x puede ser cualquier cosa:
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;
Los resultados cuando n = 3
:
x | result
----------
-4| 2
-3| 0
-2| 1
-1| 2
0| 0
1| 1
2| 2
3| 0
4| 1
Si solo necesita una distribución uniforme entre 0
y n-1
y no el operador de mod exacto, y x
los suyos no se agrupan cerca 0
, lo siguiente será aún más rápido, ya que hay más paralelismo a nivel de instrucción y el %
cálculo lento ocurrirá en paralelo con el otro partes ya que no dependen de su resultado.
return ((x >> 31) & (n - 1)) + (x % n)
Los resultados de lo anterior con 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 la entrada es aleatoria en el rango completo de un int, la distribución de ambas soluciones será la misma. Si los grupos de entrada se acercan a cero, habrá muy pocos resultados n - 1
en la última solución.
Aquí hay una alternativa:
a < 0 ? b-1 - (-a-1) % b : a % b
Esto podría ser más rápido o no que la otra fórmula [(a% b + b)% b]. A diferencia de la otra fórmula, contiene una rama, pero usa una operación de módulo menos. Probablemente sea una victoria si la computadora puede predecir un <0 correctamente.
(Editar: se corrigió la fórmula).