Java] Operator

연산자 우선순위

연산기호 결합방향 우선순위
[ ], . 👉 1(높음)
expr++, expr– 👈🏿 2
++expr, –expr, +expr, -expr, ~, !, (type) 👈🏿 3
*, /, % 👉 4
+, - 👉 5
<<, >>, >>> 👉 6
<, >, <=, >=, instanceof 👉 7
==, != 👉 8
& 👉 9
^ 👉 10
| 👉 11
&& 👉 12
|| 👉 13
? expr : expr 👈🏿 14
=, +=, -=, *=, /=, %=, &=, ^=, |=, <<=, >>=, >>>= 👈🏿 15(낮음)

논리 연산자와 Short-Circuit Evaluation(Lazy Evaluation), SCE

연산자를 사용할 때는 우선순위를 고려해야한다.

1
2
3
4
5
6
7
8
9
10
int num1 = 0, num2 = 0;
boolean result;

result = (num1 += 10) < 0 && (num2 += 10) > 0;
System.out.println("result : " + result);
System.out.println("num1 : " + num1 + ", num2 : " + num2);

result = (num1 += 10) > 0 || (num2 += 10) > 0;
System.out.println("result : " + result);
System.out.println("num1 : " + num1 + ", num2 : " + num2);

위의 소스의 결과는 참으로 재미있다.

논리 연산자에 대해서 정확히 알고 있는 사람이라면 당연한 것이지만…

&&의 경우에는 앞에 값이 false가 나왔다면 뒤의 값이 뭐가 나오는지 계산할 필요 없이 false값이 나온다.

||의 경우에는 앞에 값이 true가 나온다면 뒤의 값이 뭐가 나오는지 계산할 필요 없이 true값이 나온다.

이말은, 이러한 경우에는 뒤의 조건식은 실행해보지도 않는다는 것이다.

시간 복잡도를 고려할 때도 조건식의 순서를 따져서 놓으면 효율이 조금이나마 좋아질 수 있다는 뜻이다.

비트 연산자 그리고 비트 쉬프트 연산자

CPU에게 있어서 곱셈과 나눗셈은 매우 부담이 되는 작업이다. 비트를 이동시키는 연산은 전혀 부담되지 않는 작업이다.

Problem01.

정수 7의 비트 열을 기반으로 2의 보수를 취하면 -7이 된다. 실제로 그런지 정수 7에 대한 2의 보수를 계산하여 출력하는 프로그램을 작성하시오.

1
2
3
4
5
int num = 7;
// 10진법을 2진법으로 나타내는 방법 - Integer.toBinaryString()
System.out.println(Integer.toBinaryString(~num + 1)); //11111111111111111111111111111001
num = ~num + 1;
System.out.println(num); //-7

Problem02.

int형 정수 15678의 오른쪽에서 세 번째 비트와 다섯 번째 비트가 각각 어떻게 되는지 확인하여 출력하는 프로그램을 작성하시오.

1
2
3
4
int num = 15678;
System.out.println(Integer.toBinaryString(num)); //11110100111110
System.out.println(num >> 3 & 1); //1
System.out.println(num >> 5 & 1); //1

연산자 우선순위를 생각하였을 때 비트 쉬프트 연산자가 먼저 이뤄지고 나서 비트 연산자가 이뤄진다.

옮기고자 하는 위치만큼 비트 쉬프트 연산자를 통해 옮겨주고 나서 비트 연산자를 이용하여 해당 값이 0이면 0이 나오게 하고, 1이라면 1이 나오게 &을 사용하면 된다. bit는 0과 1만 있기에 다른 값은 고려하지 않아도 된다.

Problem03.

<< 연산은 대부분의 경우에 피연산자의 값에 2의 배수를 곱하는 결과를 보인다. 그러나 MSB[^1]를 변경시켜서 전혀 엉뚱한 결과를 보이는 경우도 있다. 음의 정수와 양의 정수를 하나씩 예로 들어서 엉뚱한 결과가 어떻게 발생하는지 설명하고, 이를 증명하기 위한 간단한 프로그램을 작성하시오.

1
2
3
4
5
6
7
8
9
10
11
12
int num = 7;
int bitset = 1 << 30;
num |= bitset;
System.out.println(num); //1073741831
System.out.println(num <<= 1); //-2147483634

int minusNum = -12;
bitset = ~0;
bitset ^= 1 << 30;
minusNum &= bitset;
System.out.println(minusNum); //-1073741836
System.out.println(minusNum <<= 1); //2147483624

01000000 00000000 00000000 00000001 이러한 비트를 왼쪽으로 한 칸씩 이동시키면 음수가 된다.

반대로, 11000000 00000000 00000000 00000001 이러한 비트를 오른쪽으로 한 칸씩 이동시키면 양수가 된다.


[^1]: 최상위 비트 MSB, most significant bit, 반대 개념은 LSB