1. Información general
En este breve tutorial, mostraremos qué es el operador de módulo y cómo podemos usarlo con Java para algunos casos de uso comunes.
2. El operador de módulo
Comencemos con las deficiencias de la división simple en Java.
Si los operandos en ambos lados del operador de división tienen el tipo int , el resultado de la operación es otro int:
@Test public void whenIntegerDivision_thenLosesRemainder() { assertThat(11 / 4).isEqualTo(2); }
La misma división nos da un resultado diferente cuando al menos uno de los operandos tiene tipo float o double:
@Test public void whenDoubleDivision_thenKeepsRemainder() { assertThat(11 / 4.0).isEqualTo(2.75); }
Podemos observar que perdemos el resto de una operación de división al dividir enteros.
El operador de módulo nos da exactamente este resto:
@Test public void whenModulo_thenReturnsRemainder() { assertThat(11 % 4).isEqualTo(3); }
El resto es lo que queda después de dividir 11 (el dividendo) entre 4 (el divisor), en este caso, 3.
Debido a la misma razón por la que no es posible una división por cero, no es posible usar el operador de módulo cuando el argumento del lado derecho es cero.
Tanto la operación de división como la de módulo arrojan una ArithmeticException cuando intentamos usar cero como operando del lado derecho:
@Test(expected = ArithmeticException.class) public void whenDivisionByZero_thenArithmeticException() { double result = 1 / 0; } @Test(expected = ArithmeticException.class) public void whenModuloByZero_thenArithmeticException() { double result = 1 % 0; }
3. Casos de uso común
El caso de uso más común para el operador de módulo es averiguar si un número dado es par o impar.
Si el resultado de la operación de módulo entre cualquier número y dos es igual a uno, es un número impar:
@Test public void whenDivisorIsOddAndModulusIs2_thenResultIs1() { assertThat(3 % 2).isEqualTo(1); }
Por otro lado, si el resultado es cero (es decir, no hay resto), es un número par:
@Test public void whenDivisorIsEvenAndModulusIs2_thenResultIs0() { assertThat(4 % 2).isEqualTo(0); }
Otro buen uso de la operación de módulo es realizar un seguimiento del índice del siguiente punto libre en una matriz circular.
En una implementación simple de una cola circular para valores int , los elementos se mantienen en una matriz de tamaño fijo.
Cada vez que queremos enviar un elemento a nuestra cola circular, simplemente calculamos la siguiente posición libre calculando el módulo del número de elementos que ya hemos insertado más 1 y la capacidad de la cola:
@Test public void whenItemsIsAddedToCircularQueue_thenNoArrayIndexOutOfBounds() { int QUEUE_CAPACITY= 10; int[] circularQueue = new int[QUEUE_CAPACITY]; int itemsInserted = 0; for (int value = 0; value < 1000; value++) { int writeIndex = ++itemsInserted % QUEUE_CAPACITY; circularQueue[writeIndex] = value; } }
Usando el operador de módulo evitamos que writeIndex se salga de los límites de la matriz, por lo tanto, nunca obtendremos una ArrayIndexOutOfBoundsException .
Sin embargo, una vez que insertemos más de QUEUE_CAPACITY elementos, el siguiente elemento sobrescribirá al primero.
4. Conclusión
El operador de módulo se usa para calcular el resto de una división entera que de otra manera se perdería.
Es útil hacer cosas simples como averiguar si un número dado es par o impar, así como tareas más complejas como rastrear la siguiente posición de escritura en una matriz circular.
El código de ejemplo está disponible en el repositorio de GitHub.