Оператор Modulo в Java

1. Огляд

У цьому короткому навчальному посібнику ми покажемо, що таке оператор modulo та як ми можемо використовувати його з Java для деяких типових випадків використання.

2. Оператор Modulo

Почнемо з недоліків простого поділу в Java.

Якщо операнди з обох сторін оператора ділення мають тип int , результатом операції є інший int:

@Test public void whenIntegerDivision_thenLosesRemainder() { assertThat(11 / 4).isEqualTo(2); }

Той самий поділ дає нам інший результат, коли принаймні один з операндів має тип float або double:

@Test public void whenDoubleDivision_thenKeepsRemainder() { assertThat(11 / 4.0).isEqualTo(2.75); }

Ми можемо помітити, що ми втрачаємо залишок операції ділення при діленні цілих чисел.

Оператор за модулем дає нам саме цей залишок:

@Test public void whenModulo_thenReturnsRemainder() { assertThat(11 % 4).isEqualTo(3); }

Залишок - це те, що залишається після ділення 11 (дивіденд) на 4 (дільник) - у цьому випадку 3.

З тієї ж причини поділ на нуль неможливий, неможливо використовувати оператор модуля, коли аргумент правої сторони дорівнює нулю.

І поділ, і операція за модулем створюють ArithmeticException, коли ми намагаємось використовувати нуль як правий бік операнда:

@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. Поширені випадки використання

Найбільш поширеним варіантом використання оператора за модулем є з’ясування непарного чи парного даного числа.

Якщо результат операції за модулем між будь-яким числом і двома дорівнює одиниці, це непарне число:

@Test public void whenDivisorIsOddAndModulusIs2_thenResultIs1() { assertThat(3 % 2).isEqualTo(1); }

З іншого боку, якщо результат дорівнює нулю (тобто залишку немає), це парне число:

@Test public void whenDivisorIsEvenAndModulusIs2_thenResultIs0() { assertThat(4 % 2).isEqualTo(0); }

Ще одним вдалим використанням операції за модулем є відстеження індексу наступного вільного місця в круговому масиві.

У простій реалізації кругової черги для значень int елементи зберігаються у масиві фіксованого розміру.

Кожного разу, коли ми хочемо просунути елемент до нашої кругової черги, ми просто обчислюємо наступну вільну позицію, обчислюючи модуль кількості елементів, які ми вже вставили плюс 1, та місткості черги:

@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; } }

Використовуючи оператор modulo, ми запобігаємо випаданню writeIndex за межі масиву, отже, ми ніколи не отримаємо ArrayIndexOutOfBoundsException .

Однак, коли ми вставляємо більше QUEUE_CAPACITY елементів, наступний елемент замінить перший.

4. Висновок

Оператор за модулем використовується для обчислення залишку цілочисельного ділення, який інакше втратив.

Корисно робити такі прості речі, як з’ясування, чи дане число парне чи непарне, а також складніші завдання, такі як відстеження наступної позиції запису в круговому масиві.

Приклад коду доступний у сховищі GitHub.