본문 바로가기

프로그래밍언어/JAVA

[JAVA] 연산자 - 논리 연산자

반응형

1. 논리 연산자 (&&, ||, !)

 

논리 연산자 '&&'  AND에 해당하며, 두 피연산자가 모두 true일 때만 true를 결과로 얻는다. '||' OR에 해당하며, 두 피연산자 중 하나만 true이어도 true를 결과로 얻는다. 논리 연산자는 피연산자로 boolean 또는 boolean 값을 결과로 하는 조건식만을 허용한다.

 

- 논리 연산자의 연산결과

 

x y x || y x && y
t t t t
t f t f
f t t f
f f f f

 

- 효율적인 연산 (short circuit ecaluation)

 

논리 연산자의 특징 중 하나는 효율적인 연산을 한다는 것이다. '||' 연산자의 경우 하나의 피연산자만 참이어도  true를 반환하기 때문에 좌측의 피연산자가 참인 경우 우측 피연산자는 평가하지 않는다. '&&' 연산자도 이와 동일하게 하나의 피연산자만 거짓이어도 거짓이기 때문에 좌측의 피연산자가 거짓인 경우 우측 피연산자는 평가하지 않는다.

 

int a = 1;
int b = 0;

System.out.println(a != 0 || ++b != 0);
// true

System.out.println(a + " " + b);
// 1 0

System.out.println(a == 0 && ++b != 0);
// false

System.out.println(a + " " + b);
// 1 0

 

위의 예제는 논리 연산자의 효율 연산에 대해 주의해야되는 부분이다. 변수 b의 경우 print문에서 ++ 연산자를 통해 값을 증가시켜주었지만 실제로는 0으로 값이 증가되지 않았음을 알 수 있다. 그 이유는 효율적인 연산에 의해서 두번의 식 모두 우측의 ++b 문이 평가되지 않았기 때문이다. 그렇기 때문에 논리 연산시에 우측 논리식이 수행되지 않는 경우도 잘 고려하여야 한다.

 

- 논리 부정 연산자 (!)

 

'!' 연산자는 true를 false로 false를 true로 변환하여 결과를 반환하는 연산자이다. 간단하게 true와 false를 반대로 바꾸는 역할을 한다. 주로 조건문과 반복문의 조건식에서 사용한다.

 

 

2. 비트 연산자 (&, |, ^, ~, <<, >>)

 

비트 연산자는 피연산자를 비트단위로 논리 연산하는데, 피연산자로 실수는 허용하지 않는다. 비트 연산을 한 결과로는 0 또는 1을 결과로 얻는다.

 

| (OR 연산자): 피연산자 중 한 쪽의 값이 1이면 1을 결과로 얻는다. 그 외에는 0을 얻는다.
& (AND 연산자): 피연산자 양 쪽이 모두 1이면 1을 결과로 얻는다. 그 외에는 0을 얻는다.
^ (XOR 연산자): 피연산자의 값이 서로 다를 때 1을 결과로 얻는다. 같은 경우에는 0을 얻는다.

 

- 비트 연산자의 연산결과

 

x y x | y x & y x ^ y
1 1 1 1 0
1 0 1 0 1
0 1 1 0 1
0 0 0 0 0

 

- 비트 전환 연산자 '~'

 

이 연산자는 논리 연산자 중 '!' 연산자와 유사하게 0을 1로 1을 0으로 변환시켜준다. 비트 전환 연산자 '~'에 의해 비트 전환이 수행되면 부호있는 타입의 피연산자는 부호가 반대로 변경된다. 즉 피연산자의 '1의 보수'를 얻을 수 있다는 것이다. 그래서 비트 전환 연산자를 '1의 보수' 연산자라고도 한다.

 

이를 이용해서 정수의 부호를 변환한 값을 얻을 수 있다. 어떤 양의 정수 p에 대해서 음의 정수를 얻으려면 ~p + 1을, 음의 정수 q에 대해서 양의 정수를 얻으려면 ~(q-1)을 계산하면 된다.

 

양의 정수 p -> ~p + 1
음의 정수 q -> ~(q - 1)

 

- 쉬프트 연산자 (<<, >>)

 

쉬프트 연산자는 피연산자의 각 자리를 우측(>>) 또는 좌측(<<)으로 이동시킨다. 예를들어 '8 << 2'를 연산해보자.

 

// 10진수 8을 2진수로 나타내면 '00001000'이다.

0 0 0 0 1 0 0 0

 

// 8의 각 자리 수들을 오른쪽 피연산자인 '2'만큼 이동시킨다.

0 0 1 0 0 0    

 

// 비트 이동에서 범위를 벗어난 값은 버려지고 빈자리는 0으로 채워진다.

0 0 1 0 0 0 0 0

 

// 최종 연산 결과 '00100000' -> 32를 값으로 얻게된다.

0 0 1 0 0 0 0 0

 

'>>' 연산자는 '<<' 연산자와 반대로 우측으로 값들을 이동시킨다. 다만 다른 점은 '<<' 연산자의 경우 빈자리를 모두 0으로 채우는 반면에, '>>' 연산자의 경우 부호 비트를 포함하여 모두 변경이 되기 때문에 피연산자가 양수인 경우에는 0으로 음수인 경우에는 1로 빈자리를 채운다.

 

// 2진수 -8

1 1 1 1 1 0 0 0

 

// -8 >> 2 -> -2 (음수이기 때문에 왼쪽에 빈자리들이 1  채워진다.)

1 1 1 1 1 1 1 0

 

8 >> 2

 

// 2진수 8

0 0 0 0 1 0 0 0

 

// 8 >> 2 -> 2 (양수이기 때문에 왼쪽에 빈자리들이 0으로 채워진다.)

0 0 0 0 0 0 1 0

 

쉬프트 연산자는 결국 2진수 기준으로 자리수를 하나씩 이동하는 것이기 때문에 값에 2를 곱하거나 2를 나누는 것과 결과가 같다.

x << n -> x * 2^n
x >> n -> x / 2^n

 

비트 연산자를 사용하면 일반적인 곱셈이나 나눗셈보다 연산의 속도가 빠르지만, 코드의 가독성이 떨어지기 때문에 단순한 연산이나 빠른 실행속도가 필요한 곳에서만 사용하는 것이 좋다.

반응형