JavaRush/Java Blog/Random EN/Bitwise Operations in Java

Bitwise Operations in Java

Published in the Random EN group
members
You are probably familiar with the word “beat”. If not, let's get to know it :) A bit is the minimum unit of measurement of information in a computer. Its name comes from the English “ binary digit ” - “binary number”. A bit can be expressed as one of two numbers: 1 or 0. There is a special number system based on ones and zeros - binary. We won’t delve into the jungle of mathematics and just note that any number in Java can be converted to its binary form. To do this you need to use wrapper classes. Bitwise operations - 1For example, here's how to do it for a number int:

public class Main {

   public static void main(String[] args) {

       int x = 342;
       System.out.println(Integer.toBinaryString(x));
   }
}
Console output:

101010110
1010 10110 (I added a space for readability) is the number 342 in binary. We actually divided this number into individual bits - zeros and ones. It is with them that we can perform operations called bitwise.
  • ~— bitwise “NOT” operator.

It works very simply: it goes through each bit of our number and changes its value to the opposite: zeros to ones, ones to zeros. If we apply it to our number 342, this is what we get: 101010110 is the number 342 in binary 010101001 is the result of the expression ~342 But since an int variable takes 4 bytes, i.e. 32 bits, in fact, the number in the variable is stored as: 00000000 00000000 00000001 01010110- the number 342 in a variable of type int in java 11111111 11111111 11111110 10101001- the result of the expression ~342 in java Let's try to do this in practice:

public class Main {

   public static void main(String[] args) {

       int x = 342;
       System.out.println(Integer.toBinaryString(~x));
   }
}
Console output:
11111111111111111111111010101001
  • &— bitwise operator “AND”

As you can see, it is written quite similar to the logical “AND” ( &&). The operator &&, as you remember, returns trueonly if both operands are true. Bitwise &works in a similar way: it compares two numbers bit by bit. The result of this comparison is the third number. For example, let's take the numbers 277 and 432: 100010101 - the number 277 in binary form 110110000 - the number 432 in binary form Next, the operator &compares the first bit of the upper number with the first bit of the lower one. Since this is an “AND” operator, the result will be equal to 1 only if both bits are equal to 1. In all other cases, the result will be 0. 100010101 & 110110000 _______________ 100010000 - result of work & We first compare the first bits of two numbers with each other, then second bits, third, etc. As you can see, only in two cases were both bits in the numbers equal to 1 (the first and fifth bits). The result of all other comparisons was 0. Therefore, in the end we got the number 100010000. In the decimal system, it corresponds to the number 272. Let's check:

public class Main {

   public static void main(String[] args) {
       System.out.println(277&432);
   }
}
Console output:

272
  • |- bitwise “OR”. The principle of operation is the same - we compare two numbers bit by bit. Only now if at least one of the bits is equal to 1, the result will be equal to 1. Let's look at the same numbers - 277 and 432:
100010101 | 110110000 _______________ 110110101 - the result of the work. | Here the result is different: only those bits that were zeros in both numbers remained zeros. The result of the work is the number 110110101. In the decimal system it corresponds to the number 437. Let’s check:

public class Main {

   public static void main(String[] args) {
       System.out.println(277|432);
   }
}
Console output:

437
We counted everything correctly! :)
  • ^- bitwise exclusive OR (also known as XOR)
We have never encountered such an operator before. But there is nothing complicated about it. It looks like a regular “or”. The difference is one: ordinary “or” returns trueif at least one operand is true. But not necessarily one - if both are there true- then the result true. But the exclusive “or” returns trueonly if one of the operands is true. If both operands are true, a regular “or” will return true(“at least one is true”), but an exclusive or will return false. That's why it's called exclusive. Knowing the principle of previous bitwise operations, you can probably easily perform the 277^432 operation yourself. But let’s better figure it out together once again :) 100010101 ^ 110110000 _______________ 010100101 - the result of the work ^ Here is our result. Those bits that were the same in both numbers returned 0 (the “one of” formula did not work). But those that formed a pair 0-1 or 1-0 eventually turned into a unit. As a result, we got the number 010100101. In the decimal system, it corresponds to the number 165. Let's see if we calculated correctly:

public class Main {

   public static void main(String[] args) {
       System.out.println(277^432);
   }
}
Console output:

165
Super! Everything is exactly as we thought :) Now is the time to get acquainted with the operations called bit shifts. The name, in principle, speaks for itself. We'll take some number and move its bits left and right :) Let's see what it looks like:

Shift left

Left shift of bits is indicated by the sign << Example:

public class Main {

   public static void main(String[] args) {
       int x = 64;//meaning
       int y = 3;//quantity

       int z = (x << y);
       System.out.println(Integer.toBinaryString(x));
       System.out.println(Integer.toBinaryString(z));
   }
}
In this example, the number x=64is called the value. It is its bits that we will shift. We will shift the bits to the left (this can be determined by the direction of the sign <<) In the binary system, the number 64 = 1000000 The number y=3is called quantity. Quantity answers the question “how many bits to the right/left should the bits of a number be shifted x?” In our example, we will shift them 3 bits to the left. To make the shift process more clear, let's look at the picture. In our example we use numbers of type int. Int's occupy 32 bits of computer memory. This is what our original number 64 looks like: Bitwise operations - 2And now we, in the literal sense of the word, take each of our bits and shift it to the left by 3 cells: Bitwise operations - 3This is what we got. As you can see, all our bits have shifted, and 3 more zeros have been added from outside the range. 3 - because we were shifting by 3. If we were shifting by 10, 10 zeros would be added. So the expression x << ymeans “shift the bits of a number хy cells to the left.” The result of our expression was the number 1000000000, which in the decimal system is equal to 512. Let's check:

public class Main {

   public static void main(String[] args) {
       int x = 64;//meaning
       int y = 3;//quantity

       int z = (x << y);
       System.out.println(z);
   }
}
Console output:

512
That's right! In theory, bits can be shifted indefinitely. But since we have the number int, there are only 32 cells available. Of these, 7 are already occupied by the number 64 (1,000,000). Therefore, if we make, for example, 27 shifts to the left, our only unit will go out of range and “overwrite”. Only zeros will remain!

public class Main {

   public static void main(String[] args) {
       int x = 64;//meaning
       int y = 26;//quantity

       int z = (x << y);
       System.out.println(z);
   }
}
Console output:

0
As we expected, the one went beyond the 32 bit cells and disappeared. We got a 32-bit number consisting of only zeros. Bitwise operations - 4Naturally, in the decimal system it corresponds to 0. A simple rule for remembering left shifts: With each left shift, the number is multiplied by 2. For example, let's try to calculate the result of the expression without pictures with bits. 111111111 << 3 We need to multiply the number 111111111 by 2 three times. As a result, we get 888888888. Let's write the code and check it:

public class Main {

   public static void main(String[] args) {
       System.out.println(111111111 << 3);
   }
}
Console output:

888888888

Right shifts

They are indicated by the sign >>. They do the same thing, only in the other direction! :) Let's not reinvent the wheel and try to do this with the same number int 64.

public class Main {

   public static void main(String[] args) {
       int x = 64;//meaning
       int y = 2;//quantity

       int z = (x >> y);
       System.out.println(z);
   }
}
Bitwise operations - 5Bitwise operations - 6As a result of the shift by 2 to the right, the two extreme zeros of our number went outside the range and were erased. We got the number 10000, which in the decimal system corresponds to the number 16. Output to the console:

16
A simple rule for remembering right shifts: Each right shift divides by two, discarding any remainder. For example, 35 >> 2 it means that we need to divide 35 by 2 2 times, discarding the remainder 35/2 = 17(discarding remainder 1) 17:2 = 8(discarding remainder 1) Total 35 >> 2should be equal to 8. Check:

public class Main {

   public static void main(String[] args) {
       System.out.println(35 >> 2);
   }
}
Console output:

8

Precedence of operations in Java

As you write or read code, you will often come across expressions in which several operations are performed simultaneously. It is very important to understand in what order they will be performed, otherwise the result may be unexpected. Since there are many operations in Java, they were all separated into a special table:

Operator Precedence

Operators Precedence
postfix expr++ expr--
unary ++expr --expr +expr ~ !
Multiplicative * / %
additive + -
shift << >> >>>
relational < > <= >=instanceof
equality == !=
bitwise AND &
bitwise exclusive OR ^
bitwise inclusive OR |
logical AND &&
logical OR ||
ternary ? :
assignment = += -= *= /= %= &= ^= |= <<= >>= >>>=
All operations are performed from left to right, but taking into account their priority. For example, if we write: int x = 6 - 4/2; first the division operation (4/2) will be performed. Although she is second in line, she has higher priority. Parentheses or square brackets change any priority to maximum. You probably remember this from school. For example, if you add them to an expression: int x = (6 - 4)/2; the subtraction will be performed first, since it is calculated in parentheses. The logical operator has &&a rather low priority, as can be seen from the table. Therefore, most often it will be executed last. For example: boolean x = 6 - 4/2 > 3 && 12*12 <= 119; This expression would be executed like this:
  • 4/2 = 2

    
    boolean x = 6 - 2 > 3 && 12*12 <= 119;
  • 12*12 = 144

    
    boolean x = 6 - 2 > 3 && 144 <= 119;
  • 6-2 = 4

    
    boolean x = 4 > 3 && 144 <= 119;
  • Next the comparison operators will be executed:

    4 > 3 = true

    
    boolean x = true && 144 <= 119;
  • 144 <= 119 = false

    
    boolean x = true && false;
  • And finally, the last operator will be executed &&.

    boolean x = true && false;

    boolean x = false;

    The addition operator ( +), for example, has higher precedence than the comparison operator !=(“not equal”);

    Therefore in the expression:

    boolean x = 7 != 6+1;

    first the operation 6+1 will be performed, then the check 7!=7 (false), and at the end the result will be assigned to falsethe variable x. Assignment generally has the lowest priority of all operations - look in the table.

Phew! Our lecture was long, but you did it! If you do not fully understand some parts of this and the previous lectures, don’t worry, we will touch on these topics more than once in the future. Here are some useful links for you:
  • Logical Operators - JavaRush lecture on logical operations. We won’t get to them any time soon, but you can read them now, there won’t be any harm
Comments
  • Popular
  • New
  • Old
You must be signed in to leave a comment
This page doesn't have any comments yet