Как найти остаток от деления java

division

Данная статья:

  • написана командой Vertex Academy. Надеемся, что она Вам будет полезна. Приятного прочтения!
  • это одна из статей из нашего «Самоучителя по Java»

Ещё со школы мы знакомы с таким понятием как обычное деление:

6 : 2 =3,

12 : 6 =2

и т.д.

С этим все понятно. А что же это за «зверь» такой, деление по модулю ? И звучит то так угрожающе.  А на самом деле всё очень и очень просто. Давайте разбираться.
Что Вам нужно понимать:

  1. Деление по модулю – это оператор

Как работает оператор сложения, вычитания и т.д. наверняка Вы уже знаете. А вот за что отвечает деление по модулю поймёте буквально через пару минут.  Немного терпения.

Operators Vertex Academy

  1. Деление по модулю обозначается вот таким знаком: %
  2. Деление по модулю иногда называют mod. То есть если увидите название mod, знайте, речь идет об операторе деление по модулю.
  3. В чём суть оператора?  Деление по модулю даёт остаток от деления. 

Давайте посмотрим на примерах как это работает.

Пример №1

Необходимо разделить 9 на  4, используя:

  • обычное деление, как нас учили в школе
  • деление по модулю

Mod Example1 Vertex Academy

Логику работы оператора деления по модулю Вы уже поняли. Самое время попробовать запустить пример на своём компьютере:

class Test {

public static void main(String[] args) {

int n = 9;

int k = 4;

int m = n%k;

System.out.println(m);

}

}

Если Вы запустите этот код на своём компьютере, то в консоль будет выведено такое число:

1

Пример №2

Необходимо разделить 17 на 5, используя:

  • обычное деление, как нас учили в школе
  • деление по модулю

Mod Example2 Vertex Academy

И пробуем теперь запустить программу на компьютере:

class Test {

public static void main(String[] args) {

int n = 17;

int k = 5;

int m = n%k;

System.out.println(m);

}

}

Если Вы запустите этот код на своём компьютере, то в консоль будет выведено такое число:

2

Пример №3

Необходимо разделить 21 на 7, используя:

  • обычное деление, как нас учили в школе
  • деление по модулю

Mod Example3 Vertex Academy

И пробуем теперь запустить программу на компьютере:

class Test {

public static void main(String[] args) {

int n = 21;

int k = 7;

int m = n%k;

System.out.println(m);

}

}

Если Вы запустите этот код на своём компьютере, то в консоль будет выведено такое число:

0

Пример №4

Необходимо разделить 7.6 на 2.9, используя:

  • обычное деление, как нас учили в школе
  • деление по модулю

Mod Example4 Vertex Academy

И пробуем теперь запустить программу на компьютере:

class Test {

public static void main(String[] args) {

double n = 7.6;

double k = 2.9;

double m = n%k;

System.out.println(m);

}

}

Если Вы запустите этот код на своём компьютере, то в консоль будет выведено число, близкое к 1.8. Например, Вы можете увидеть какое-то такое число: 1.7999999999999998. Из-за определённых особенностей Java, которые мы будем с Вами рассматривать позже в других статьях, на разных компьютерах число будет немного отличаться. Но оно будет близкое по значению к 1.8

Итак, как Вы уже поняли, оператор деления по модулю вычисляет остаток от деления.

  1. Применяется к таким типам переменных:
  • Byte, short, Int, long – целочисленный тип переменных
  • Float, Double – числа с плавающей точкой
  • Отрицательные и положительные числа

Есть небольшой нюанс при использовании оператора деления по модулю с отрицательными и положительными числами.

Работает простое правило:

  1. Отбрасываете знак минуса
  2. Делите числа как обычно
  3. А далее, если первое число (делимое), было со знаком минус, к результату добавляете знак минус.

Пример №5

Mod Example5 Vertex Academy

И пробуем теперь запустить программу на компьютере — один из описанных выше примеров:

class Test {

public static void main(String[] args) {

int n = 9;

int k = 4;

int m = n%k;

System.out.println(m);

}

}

Если Вы запустите этот код на своём компьютере, то в консоль будет выведено такое число:

-1

Вот и всё —  теперь Вы уже знаете, что такое деление по модулю в Java.


Надеемся, что наша статья была Вам полезна. Также есть возможность записаться на наши курсы по Java в Киеве. Обучаем с нуля.

По всем вопросам звоните:

+38 050 205 77 99

+38 098 205 77 99

Или читайте информацию по нашим курсам Java c нуля у нас на сайте.

Я уже однажды расписывал операции в Java. В этой статье я акцентрирую внимание на операцию взятия остатка от деления, так как её работа отличается в различных языках программирования и иногда порождает недопонимание.

Операция взятия остатка 
% в Java работает не только с целыми числами, но и с числами с плавающей точкой.

Для целых чисел операция взятия остатка работает по такому принципу, что результат операции будет таким, что будет выполняться равенство:

(a / b) * b + (a % b) == a

Это равенство действует даже в том случае, если левый операнд будет наименьшим отрицательным числом для своего типа, а операнд в правой части будет равен -1 (тогда результатом будет 0).

Результатом операции взятия остатка для целых чисел в Java может быть отрицательное число только в том случае, если левый операнд будет отрицательным числом, а также результат может быть положительным только в том случае, если операнд в левой части будет положительным числом.

Если в правой части операции взятия остатка для целочисленных операндов в Java стоит 0, то результатом будет
ArithmeticException.

Примеры работы операции взятия остатка для целочисленных операндов (выполнено в JShell):

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

$ ./jshell

|  Welcome to JShell Version 10.0.1

|  For an introduction type: /help intro

jshell> 5 % 3

$1 ==> 2

jshell> 5 / 3

$2 ==> 1

jshell> 5 % (3)

$3 ==> 2

jshell> 5 / (3)

$4 ==> 1

jshell> (5) % 3

$5 ==> 2

jshell> (5) / 3

$6 ==> 1

jshell> (5) % (3)

$7 ==> 2

jshell> (5) / (3)

$8 ==> 1

Как я уже говорил, в Java операция взятия остатка
% работает и с числами с плавающей точкой (
float и
double). Согласно спецификации языка Java операция взятия остатка для чисел с плавающей точкой работает не так, как это принято в IEEE 754, но если очень нужно то можно использовать метод
Math.IEEEremainder.

В Java операция взятия остатка
% работает согласно следующим правилам:

  • Если один из операндов равен NaN, то результат операции будет NaN.
  • Если результат не NaN, то знаком результата будет знак операнда в левой части.
  • Если операнд в левой части Infinity, или операнд в правой части равен нулю, или выполняются оба условия, то результат будет равен операнду в левой части.
  • Если операнд в левой части конечен, а операнд в правой части Infinity, то результат будет равен операнду в левой части.
  • Если операнд в левой части равен нулю, а операнд в правой части конечен, то результат будет равен операнду в левой части.
  • Во всех остальных случаях результат
    r взятия остатка от операнда
    n при делении на
    d определяется по математической формуле r = n — (d × q), где q будет целым числом, которое отрицательно только в случае, если n / d отрицательно, и положительно, если  n / d положительно, и его размер максимально возможный, но не превышающий  отношение n и d. Пример: 0,5 ÷ 0,3 = 1,6, тогда q будет положительным, так как 1,6 положительно, а наибольший размер, не превышающий 1,6 будет 1, то q = 1, а значит r = 0,5 — (0,3 × 1) = 0,2.

Операция взятия остатка для чисел с плавающей точкой никогда не приводит к возникновению Exception-ов.

Примеры операции взятия остатка для чисел с плавающей точкой:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

$ ./jshell

|  Welcome to JShell Version 10.0.1

|  For an introduction type: /help intro

jshell> Double.NaN % 3.0

$1 ==> NaN

jshell> 5.0 % Double.NaN

$2 ==> NaN

jshell> Double.NaN % Double.NaN

$3 ==> NaN

jshell> Double.POSITIVE_INFINITY % 0.0

$4 ==> NaN

jshell> 5.0 % Double.POSITIVE_INFINITY

$5 ==> 5.0

jshell> 5.0 % Double.NEGATIVE_INFINITY

$6 ==> 5.0

jshell> 0.0 % 3.0

$7 ==> 0.0

jshell> 0.0 % 3.0

$8 ==> 0.0

jshell> 5.0 % 3.0

$9 ==> 2.0

jshell> 5.0 % (3.0)

$10 ==> 2.0

jshell> (5.0) % 3.0

$11 ==> 2.0

jshell> (5.0) % (3.0)

$12 ==> 2.0

jshell> 5.1 % 3.2

$13 ==> 1.8999999999999995

jshell> 5.12 % 3.4

$14 ==> 1.7200000000000002

Имейте в виду, что в других языках операция взятия остатка может работать по-другому. В этой статье описана работа операции взятия остатка 
% для языка Java.

Остаток от деления — это целое число, полученное в результате операции деления с остатком. Если остаток от деления равен, то число делится на делитель нацело. В Java остаток от деления одного числа на другое можно получить при помощи оператора %

System.out.println(3 % 2); // => 1
System.out.println(4 % 2); // => 0

Рассмотрим работу оператора на примере. Поделим число 78 на 33. При делении мы получим неполное частное 2 и остаток от деления. Чтобы убедиться в правильности результата, нужно неполное частное умножить на делитель и прибавить остаток от деления:

33 * 2 + 12 = 78

Since everyone else already gave the answer, I’ll add a bit of additional context. % the «modulus» operator is actually performing the remainder operation. The difference between mod and rem is subtle, but important.

(-1 mod 2) would normally give 1. More specifically given two integers, X and Y, the operation (X mod Y) tends to return a value in the range [0, Y). Said differently, the modulus of X and Y is always greater than or equal to zero, and less than Y.

Performing the same operation with the «%» or rem operator maintains the sign of the X value. If X is negative you get a result in the range (-Y, 0]. If X is positive you get a result in the range [0, Y).

Often this subtle distinction doesn’t matter. Going back to your code question, though, there are multiple ways of solving for «evenness».

The first approach is good for beginners, because it is especially verbose.

// Option 1: Clearest way for beginners
boolean isEven;
if ((a % 2) == 0)
{
  isEven = true
}
else
{
  isEven = false
}

The second approach takes better advantage of the language, and leads to more succinct code. (Don’t forget that the == operator returns a boolean.)

// Option 2: Clear, succinct, code
boolean isEven = ((a % 2) == 0);

The third approach is here for completeness, and uses the ternary operator. Although the ternary operator is often very useful, in this case I consider the second approach superior.

// Option 3: Ternary operator
boolean isEven = ((a % 2) == 0) ? true : false;

The fourth and final approach is to use knowledge of the binary representation of integers. If the least significant bit is 0 then the number is even. This can be checked using the bitwise-and operator (&). While this approach is the fastest (you are doing simple bit masking instead of division), it is perhaps a little advanced/complicated for a beginner.

// Option 4: Bitwise-and
boolean isEven = ((a & 1) == 0);

Here I used the bitwise-and operator, and represented it in the succinct form shown in option 2. Rewriting it in Option 1’s form (and alternatively Option 3’s) is left as an exercise to the reader. ;)

#статьи

  • 17 фев 2023

  • 0

Знакомимся с основными инструментами языка и учимся работать с ними на практике.

Иллюстрация: Оля Ежак для Skillbox Media

Лев Сергеев

Программист, музыкант. Знает Java, C# и Unity3D, но не собирается останавливаться на достигнутом.

Все мы со школы знакомы с математическими знаками + (плюс),  (минус), = (равно) и так далее. В Java и других языках программирования эти символы называются операторами. Они нужны для того, чтобы сообщить компилятору, какое действие совершать с операндами — числами, строками, объектами и другими значениями по обе стороны оператора.

Скриншот: Лев Сергеев для Skillbox Media

Например, на картинке выше оператор + говорит компилятору: «Сложи два числа». Но на практике чисел в выражении может быть разное количество — и одно, и два, и три. В этих случаях и операторы будут называться по-разному: унарные — что-то делают с одним операндом, бинарные — с двумя, и тернарные — с тремя.

В этой статье рассмотрим не только эти, но все основные виды операторов в Java:

  • Присваивания
  • Арифметические
  • Унарные
  • Сравнения
  • Логические
  • Тернарный
  • Оператор instanceof
  • Побитовые
  • Составные операторы присваивания

Ещё поговорим о приоритетах операторов — разберёмся, в каком порядке они выполняются. Если вы хотите просто освежить в памяти суть работы разных операторов, можете сразу перейти к шпаргалке в конце статьи.

Оператор присваивания в Java — это знак = (равно). Его задача — переложить значение переменной справа в переменную слева:

Скриншот: Лев Сергеев для Skillbox Media

Вот как это выглядит в коде (в комментариях — разбор синтаксиса):

int x = 1;    // Объявляем числовую переменную 'x' со значением 1

boolean a, b; // Объявляем логические переменные 'a' и 'b'
a = b = true;

Что происходит: значение true присваивается переменной b. В свою очередь, значение переменной b присваивается переменной a.

Эти операторы выполняют простые арифметические действия: сложение, вычитание, умножение, деление и деление с остатком. Все арифметические операторы являются бинарными — то есть работают только с двумя значениями.

Что делает: складывает два операнда.

Ещё этот оператор применяется при соединении двух строк в одну. Например, в Java можно выполнить выражение «Я люблю» + «Москву» и получить «Я люблю Москву». Такая операция в программировании называется конкатенацией.

// Сложение чисел
System.out.println(10 + 2);     // Вывод: 12

// Конкатенация строк
System.out.println("A" + "B");  // Вывод: AB

// Сложение двух переменных типа 'char' 
System.out.println('a' + 'b');  // Вывод: 195

В Java типы данных char, byte и short при вычислениях неявно приводятся к типу int (целое число), поэтому с ними можно работать как с обычными числами. При этом тип данных char в Java отвечает за символы Unicode — каждый символ обозначает какое-то число. Например, символ a равен числу 97, а b — 98, поэтому в нашем примере и получилось значение 195.

Что делает: вычитает из левого операнда правый.

// Вычитание чисел
System.out.println(10 - 2);     // Вывод: 8

Что делает: возвращает произведение операндов.

// Умножение чисел
System.out.println(10 * 2);     // Вывод: 20

Что делает: делит левый операнд на правый.

// Деление без остатка
System.out.println(10 / 2);     // Вывод: 5
System.out.println(11 / 2);     // Вывод: 5

// Деление на 'double' 
System.out.println(11 / 2d);    // Вывод: 5.5

А вот что будет, если попробовать поделить на ноль в Java:

System.out.println(10 / 0);     // Ошибка
Вывод:    Exception in thread "main" java.lang.ArithmeticException: / by zero

Делить число на ноль нельзя! Программа завершится, выбросив исключение. Но если привести выражение к типу ‘double’ (число с плавающей запятой), то вы получите «бесконечность»:

System.out.println(10 / 0d);    // Вывод: Infinity

Что делает: возвращает остаток от деления.

// Деление чисел по модулю (получение остатка от деления)
System.out.println(10 % 2);     // Вывод: 0
System.out.println(11 % 2);     // Вывод: 1

Эти операторы в Java тоже можно отнести к арифметическим, но есть нюанс — они работают только с одним операндом. Поэтому их и называют унарными.

Что делают: меняют значение числа на положительное или отрицательное.

int positive = 1;
int negative = -2;

// Унарный минус
System.out.println(-positive);    // Вывод: -1

// Унарный плюс
System.out.println(+negative);    // Вывод: 2

Что делают: инкремент — увеличивает значение переменной на единицу, а декремент — уменьшает.

В свою очередь, у декремента и инкремента есть две формы: префиксная и постфиксная. Звучит сложно, но на деле всё просто:

  • Префиксные операторы (++x) сразу меняют значение переменной и подставляют его в выражение.
  • Постфиксные операторы (x++) делают наоборот — сначала используют старое значение переменной и только потом подставляют новое.

int a = 0, b = 0, c = 0, d = 0;

// Префиксный инкремент/декремент
System.out.println(++a);    // Вывод: 1
System.out.println(--b);    // Вывод: -1

// Постфиксный (значение переменных изменится после вывода в консоль)
System.out.println(c++);    // Вывод: 0
System.out.println(d--);    // Вывод: 0

Инкременты и декременты часто используют в циклах в качестве счётчика, когда нужно по очереди вывести все числа в каком-то диапазоне:

/*  Префиксный инкремент в цикле.
Сначала переменная i увеличивается на 1, а потом подставляется в цикл
*/
int i = 0;
while (++i < 3){
   System.out.print(i);
}
Вывод:  12

/*  Постфиксный инкремент в цикле.
Сперва выполняется цикл c начальным значением i, и только потом i увеличивается на 1:*/
int i = 0;
while (i++ < 3){
   System.out.print(i);
}
Вывод:  123

Подробнее о декрементах и инкрементах можно почитать в нашей статье — рассказываем, как решать сложные выражения с этими операторами.

В Java есть ещё два унарных оператора: ! — логическое отрицание, и ~ — побитовое отрицание, но их мы рассмотрим чуть позже, когда будем разбираться с логическими и побитовыми операторами.

Что делают: сравнивают два операнда и выясняют отношения между ними — что больше, что меньше, что чему равняется. При вычислении такие операторы возвращают значение типа boolean:

  • true (правда);
  • false (ложь).

Всего в Java шесть операторов сравнения:

Оператор Что означает
== Равно
> Больше, чем
< Меньше, чем
>= Больше или равно
<= Меньше или равно
!= Не равно

Давайте посмотрим, как выглядят операторы сравнения в коде — попробуем сравнить два целых числа и вывести результаты на экран:

// В этом примере мы спрашиваем, равен ли ноль единице: 
System.out.println(1 == 0);     // Вывод: false (ложь)

// А здесь — больше ли единица, чем ноль:
System.out.println(1 > 0);      // Вывод: true (правда)

// Единица меньше или равна нулю?
System.out.println(1 <= 0);     // Вывод: false (ложь)

Ещё операторы сравнения часто используют в условных конструкциях. Это когда, в зависимости от условий, выполняется какой-то один блок кода. В этом случае, помимо операторов сравнения, нам понадобятся операторы ветвления: if-else, switch и так далее. Например, здесь мы просим Java напечатать слово true, если 1 не равно 0:

// Если '1' не равно '0', то напечатать "true"
if(1 != 0) System.out.println("true");   // Вывод: true

Подробнее об операторах сравнения и условных конструкциях можно почитать в этой статье.

Что делают: комбинируют логические значения типа true и false.

В отличие от операторов сравнения, логические операторы работают не с отдельными числами, а с результатами выражений. Их часто используют в условных конструкциях — например, можно поставить рядом два выражения и выполнить какой-то блок кода, если одно из них возвращает true.

Всего в Java шесть логических операторов, но чаще всего используют эти четыре:

Символ Логический оператор Что означает
&& И (AND) Возвращает true, когда оба операнда true.
|| ИЛИ (OR) Возвращает true, когда хотя бы один операнд — true.
^ ИСКЛЮЧАЮЩЕЕ ИЛИ (XOR) Возвращает true, когда один операнд true, а второй — false.
! НЕ (NOT) Инвертирует true в false и наоборот. Это унарный оператор — он работает только с каким-то одним выражением.

В качестве примера сравним несколько выражений:

// AND — логическое умножение
boolean a = (6 > 5) && (7 > 4); 
System.out.println(a);
// Результат: true, так как оба выражения  true

// OR — логическое сложение
boolean b = (6 > 5) || (7 > 4); 
System.out.println(b);
// Результат: true, так как одно из выражений true

// XOR — логическое вычитание
boolean c = (6 > 8) ^ (6 > 7);
System.out.println(c); 
// Результат: false, так как оба выражения — false

// NOT — логическое отрицание
boolean d = (6 > 5);
System.out.println(!d);  
// Результат: false, так как изначальное выражение — true

Как это работает. Допустим, у нас есть конструкция (6 > 5) && (7 > 4). Когда мы начнём её выполнять, компилятор сначала проверит условия первого выражения, затем — второго. При этом оператор && устроен так, что если оба выражения истинны, то он и сам вернёт true. А это как раз наш случай, потому что и 6 больше 5, и 7 больше 4.

Что делает: сокращает условную конструкцию if-else до одной строчки.

Тернарный оператор (от латинского слова ternarius — «тройной») — это языковая конструкция, которая состоит из трёх операндов: логического условия и двух выражений. Если результат логического условия будет true, выполнится первое выражение, если false — второе. Записываются тернарные операторы так:

Скриншот: Лев Сергеев для Skillbox Media

Фишка в том, что таким образом мы можем записать конструкцию if-else всего одной строчкой. Допустим, нам нужно проверить булеву переменную condition — если она возвращает true, то переменная a = 100, а если false, то a = 200. Посмотрите, как легко это можно сделать с помощью тернарного оператора:

Слева — классическая конструкция if-else, справа — запись с помощью тернарного оператора
Скриншот: Лев Сергеев для Skillbox Media

Кажется, что эти if-else теперь вообще больше не нужны. Мол, ставь везде тернарные операторы, и дело с концом. Однако в больших программах со сложной логикой это может повредить читаемости кода. Это в нашем примере выражение простое — а представьте, если в каждое выражение положить ещё по одному оператору. Получится неопрятно. Другому разработчику, который будет читать наш код, разобраться будет сложно.

Поэтому тернарные операторы рекомендуют использовать в тех случаях, когда условие простое и легко проверяется. А во всех остальных случаях прибегать к привычным «ифам» и «элсам».

Что делает: проверяет, принадлежит ли объект к какому-то классу или интерфейсу, и возвращает булево значение — то есть true или false.

Использование instanceof актуально, когда нужно проверить родителя объекта прямо во время выполнения программы. Например, если объекты приходят в ваш код из базы данных или другого потока выполнения и вам нужно убедиться, что к ним можно применять методы какого-то класса. Записывается instanceof так:

Скриншот: Лев Сергеев для Skillbox Media

import java.io.Serializable;

public class Main {
   public static void main(String[] args) {

       // Объявляем ссылку типа 'Object' и кладём объект типа 'String'
       Object object = new String();

       // 'true', так как в 'object' лежит объект 'String'
       System.out.println(object instanceof String);

       // 'true', так как 'object' наследник 'Object'
       System.out.println(object instanceof Object);

       // 'false', так как 'object' не принадлежит классу 'Math'
       System.out.println(object instanceof Math);

       // 'true', так как в 'object' лежит объект 'String',
       // а 'String' реализует интерфейс 'Serializable'
       System.out.println(object instanceof Serializable);
   }
}

Зачем нужны: чтобы писать алгоритмы, работающие с битами, — например, это полезно в криптографии и шифровании данных.

В Java существует семь побитовых операторов. Четыре из них отвечают за побитовые вычисления. Они похожи на логические операции, только вместо true и false вы имеете дело с нулями и единицами в двоичной системе счисления. Каждый разряд вычисляется поочерёдно — но в отличие от математики, когда складываются две единицы, результат не переносится на старший разряд и ответом будет 1. Это как если бы мы считали столбиком, а всё, что «в уме», — выкидывали.

Выглядит так:

Скриншот: Лев Сергеев для Skillbox Media

Побитовые операторы вычисления бывают следующими:

Символ Что означает
& Побитовое И (AND) — умножение
| Побитовое ИЛИ (OR) — сложение
^ Побитовое ИСКЛЮЧАЮЩЕЕ ИЛИ (XOR) — вычитание
~ Побитовое НЕ (NOT) — отрицание

Чтобы посмотреть, как работают побитовые вычисления в Java, переведём несколько десятичных чисел в двоичную систему счисления:

// Переводим числа от 1 до 8 в двоичную систему
// 1 = 001      5 =  101
// 2 = 010      6 =  110
// 3 = 011      7 =  111
// 4 = 100      8 = 1000

Теперь попробуем выполнить с ними логические операции:

// 100 побитово умножить на 011 = 000
System.out.println(4 & 3);  //  Вывод: 0

// 010 побитово сложить с 011 = 011
System.out.println(2 | 3);  //  Вывод: 3

// из 010 побитово вычесть 001 = 011
System.out.println(2 ^ 1);  //  Вывод: 3

// 000 инвертировать в ... 111 ? 
System.out.println(~0);     //  Вывод: -1

В последнем примере мы видим, что при побитовом отрицании числа 0, почему-то получается -1. Тут есть два нюанса:

  • 0 в нашем примере имеет тип int и занимает в памяти 4 байта — то есть 32 бита.
  • Самый старший бит переменной (первый слева) является знаковым. Если он равен 0, то число будет положительным, а если 1 — отрицательным.

Скриншот: Лев Сергеев для Skillbox Media

Если разобраться в концепции старшего бита, можно без труда освоить три оставшихся побитовых оператора, которые называются операторами смещения битов:

Символ Что означает
<< Сдвиг битов влево
>> Сдвиг битов вправо
>>> Беззнаковый сдвиг битов вправо

Операторы сдвига смещают все биты в левую или правую сторону, но делают это по-разному:

  • >> не трогает старший бит, оставляя число с тем же знаком (отрицательным или положительным). Ячейки отрицательных чисел при >> заполняются единицами.
  • >>> и << — затрагивают все биты. Освободившиеся ячейки справа заполняются нулями. Наполнение ячеек слева зависит от знака и оператора.

Звучит сложно, на деле — тоже сложно. Но попробуем разобраться на примере — разложим какое-то десятичное число на биты и посмотрим, как работает смещение битов.

В Java есть метод toBinaryString(), который показывает, как выглядят десятичные числа в двоичной системе. Но двоичные числа — это ещё не биты. Например, число 2 занимает 32 бита, но если обработать его методом toBinaryString(), на экране появятся только два из них: 1 и 0. Оставшиеся 30 нулей просто «обрезаются». Это происходит по той же причине, по которой мы, например, не пишем десятичное число 9 как 009.

System.out.print(Integer.toBinaryString(2));
Вывод:  10

Поэтому, чтобы лучше разобраться в работе побитовых операторов, лучше использовать модифицированный метод BinaryString, который раскладывает на биты уже так, как надо:

// Метод добавляет к бинарному значению все недостающие биты и выводит их на экран
public static void printBinaryString(int hexNumber){
   String bits = Integer.toBinaryString(hexNumber);
   String allBits = "00000000000000000000000000000000"
                          .substring(0, 32 - bits.length()) + bits;

   System.out.printf("%11d : %sn", hexNumber, allBits);
}

Сдвинув биты числа 1 два раза влево, мы получаем 4. А если потом сдвинуть их ещё 29 раз, получится минимальное значение типа int: –2 147 483 648.

printBinaryString(1);
printBinaryString(1 << 2);  // Смещаем биты числа '1' влево на 2 позиции
printBinaryString(4 << 29); // Смещаем биты числа '4' влево на 29 позиций
Вывод:    1 : 00000000000000000000000000000001
          4 : 00000000000000000000000000000100
-2147483648 : 10000000000000000000000000000000

Теперь попробуем сдвинуть наши биты уже в обратную сторону. Обратите внимание, как различается работа >> и >>>. В первом случае всё заполнится единицами и вы получите минусовое значение, а во втором на выходе будут просто нули.

printBinaryString(Integer.MIN_VALUE);

// Смещаем биты числа '-2147483648' вправо на 16
printBinaryString(Integer.MIN_VALUE >> 16);  

// Беззнаковое смещение битов числа '-2147483648' вправо на 16
printBinaryString(Integer.MIN_VALUE >>> 16);
Вывод:    -2147483648 : 10000000000000000000000000000000
               -32768 : 11111111111111111000000000000000
                32768 : 00000000000000001000000000000000

Как это работает. С помощью операторов >> и >>> мы сдвигаем все биты числа вправо. Но при обычном сдвиге (>>) отрицательное число остаётся отрицательным, потому что мы не трогаем старший бит. При беззнаковом сдвиге (>>>) наоборот — отрицательное станет положительным, потому что мы затронем эту значимую единицу.

Зачем нужны: чтобы записывать выражения короче и автоматически приводить операнды к единому типу.

В Java есть сокращённые формы операторов присваивания — составные. Такие операторы выполняют действие между x и y, а получившееся значение помещают в x. Выглядят составные операторы так:

Скриншот: Лев Сергеев для Skillbox Media

Плюс составных операторов в том, что они записываются короче и неявно приводят переменные к одному типу, если эти типы различаются. Например, в сокращённом варианте можно сложить дроби и числа без приведения, и нам за это ничего не будет. А в полной записи будет ошибка:

int x = 1;
double y = 3.1415d;

x = x + y;        // Эта строка не скомпилируется
x += y;           // А здесь всё хорошо

// Оператор += в развёрнутом виде
x = (int)(x + y); 

У каждого оператора Java есть свой приоритет. Чем он выше, тем раньше оператор выполнится в выражении. Бинарные и тернарный операторы (кроме присваивания) выполняются слева направо, а остальные (унарные и присваивания) — справа налево.

Приоритет
(снизу вверх)
Группа Операторы
13 Постфиксные x++ x––
12 Унарные ++x ––x +x –x ~x !x
11 Мультипликативные * / %
10 Аддитивные +
9 Сдвига битов << >> >>>
8 Сравнения < > <= >= instanceof
7 Равенства == !=
6 Побитовое И &
5 Побитовое исключающее ИЛИ ^
4 Побитовое ИЛИ |
3 Логическое И &&
2 Логическое ИЛИ ||
1 Тернарный ? :
0 Присваивания = += -= *= /= %=
&= ^= |=
<<= >>= >>>=

Мы рассмотрели все основные операторы в Java и их работу на примерах. Попробуем кратко резюмировать, что нужно вынести из этой статьи:

  • Оператор — это языковая конструкция, которая выполняет действие над операндом.
  • Операнд — это число, переменная, объект и так далее, с которыми оператор совершает какие-то действия (например, арифметическое и логическое).
  • Операторы бывают унарные, бинарные и тернарные — это зависит от того, сколько операндов они обрабатывают.
  • Арифметические операторы нужны для простых математических действий: сложения, вычитания, умножения, деления и деления с остатком.
  • Унарные операторы работают только с одним операндом. Это унарные минус и плюс, инкремент, декремент, логическое и побитовое отрицание.
  • Операторы сравнения сопоставляют значения двух операторов и возвращают ответ — true или false.
  • Логические операторы заточены уже не на числа, а на целые выражения — и на их основе создают сложные условия, например, для работы в циклах.
  • Тернарный оператор умеет работать сразу с тремя операндами: условием и двумя выражениями. То есть им вполне можно заменить ветвления типа if-else.
  • Оператор instanceof определяет принадлежность объекта к классу.
  • Побитовые операторы нужны для проведения операций с битами — если упростить, то с нулями и единицами в двоичной системе счисления.
  • Составные операторы неявно приводят типы данных, если они разные.
  • У каждого оператора есть свой приоритет.

Для более глубокого понимания темы можно почитать другие наши статьи: «Тип Boolean и операторы сравнения в Java» и «Логические операторы в Java». А если хотите совсем хорошо разобраться, почитайте официальную документацию Java — это вообще лучший способ освоить язык со всеми его тонкостями.

Научитесь: Профессия Java-разработчик
Узнать больше

Понравилась статья? Поделить с друзьями:
  • Как найти уравнение графика по 2 точками
  • Точка сюань чжун как найти
  • Как найти разницу в паскале
  • Как найти коэффициент покрытия инвестиций по балансу
  • Как найти срок действия документа