반응형
5. 논리 연산자
- ||(OR결합) 피연사자 중 어느 한 쪽만 true이면 true를 결과로 얻는다.
- &&(AND결합) 피연산자 양쪽 모두 true이어야 true를 결과로 얻는다.
- [예제] 사용자로부터 문자를 입력받아서 숫자, 영문자(소문자), 영문자(대문자) 구별하기
public class _16_LogicalOperator {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
char ch = ' ';
System.out.print("문자를 하나 입력하세요 : ");
String input = scanner.nextLine();
ch = input.charAt(0);
if ('0' <= ch && ch <= '9') {
System.out.printf("숫자입니다.%n");
} else if ('A' <= ch && ch <= 'Z') {
System.out.printf("영문자(대문자)입니다.%n");
} else if ('a' <= ch && ch <= 'z') {
System.out.printf("영문자(소문자)입니다.%n");
} else {
System.out.println("잘못된 값을 입력하셨습니다. 프로그램을 종료합니다.");
}
}
}
// 결과
문자를 하나 입력하세요 : 3
숫자입니다.
문자를 하나 입력하세요 : a
영문자(소문자)입니다.
문자를 하나 입력하세요 : F
영문자(대문자)입니다.
문자를 하나 입력하세요 : ㄱ
잘못된 값을 입력하셨습니다. 프로그램을 종료합니다.
5.1 효율적인 연산
- 같은 조건식이라도 피연산자의 위치에 따라 연산속도가 달라질 수 있다.
OR 연산의 경우 연산결과가 ‘참’일 확률이 높은 피연산자를 왼쪽! - ex) 대소문자 확인 시 사용자가 소문자 입력을 할 확률이 높을 경우
(’a’ <= ch && ch <= ‘z’) || (’A’ <= ch && ch <= ‘Z’)
5.2 비트 연산자
5.2.1 & | ^ ~ << >>
- |(OR) : 피연산자 중 한 쪽의 값이 1이면 1. 그 외에 0
- &(AND) : 피연산자 양 쪽이 모두 1이어야만 1. 그 외에 0
- ^(XOR) : 피연산자의 값이 서로 다를 때만 1. 같을 때 0, ^ : 배타적 XOR(eXclusive OR)이라 부름
- [예제] 0xAB의 마지막 4 bit를 ‘F’로 변경하는 방법 ‘|’ : 0xAB | 0xF = ?
0xAB : 1 0 1 0 1 0 1 1
0xF : 0 0 0 0 1 1 1 1
|) ——————————————
1 0 1 0 1 1 1 1 → 0xAF
- [예제] 특정 비트의 값을 뽑아낼 때 사용하는 ‘&’ : 0xAB & 0xF = ?
0xAB : 1 0 1 0 1 0 1 1
0xF : 0 0 0 0 1 1 1 1
&) ——————————————
0 0 0 0 1 0 1 1 → 0xB
- [예제] 같은 값으로 두고 XOR 연산을 시행하면 원래의 값으로 돌아오는 특징 → 간단한 암호화에 사용 ‘^’ : 0xAB ^ 0xF = ?
0xAB : 1 0 1 0 1 0 1 1
0xF : 0 0 0 0 1 1 1 1
^) ——————————————
1 0 1 0 0 1 0 0 → 0xA4
0xA4 : 1 0 1 0 0 1 0 0
0xF : 0 0 0 0 1 1 1 1
^) ——————————————
1 0 1 0 1 0 1 1 → 0xAB
→ 편의상 2진수 8자리로 표현했지만 int 타입(4 byte)간의 연산이라 32자리로 표현하는 것이 맞다.
또한 비트 연산에서도 피연산자의 타입을 일치시키는 ‘산술 변환’이 일어날 수 있음.
5.2.2 비트 전환 연산자 ~
- 이 연산자는 피연산자를 2진수로 표현했을 때, 0은 1로, 1은 0으로 바꾼다. 논리부정 연산자 ‘!’와 유사하다.
- ‘~’에 의해 ‘비트 전환’이 되고 나면 피연산자의 ‘1의 보수’를 얻을 수 있음 → ‘1의 보수’ 연산자라고도 부른다.
- [예제] 10진수를 2진수로 변환하는 toBinaryString()을 이용하여 비트 전환 연산자 출력
public class _17_BitSwitchingOperator {
public static void main(String[] args) {
byte p = 10;
byte n = -10;
System.out.printf(" p =%d \\t%s%n", p, toBinaryString(p));
System.out.printf(" p =%d \\t%s%n", ~p, toBinaryString(~p));
System.out.printf(" p =%d \\t%s%n", ~p+1, toBinaryString(~p+1));
System.out.printf(" p =%d \\t%s%n", ~~p, toBinaryString(~~p));
System.out.println();
System.out.printf(" n =%d%n", n);
System.out.printf("~(n-1) =%d%n", ~(n-1));
}
// 10진 정수를 2진수로 변환하는 메서드
static String toBinaryString(int x) {
String zero = "00000000000000000000000000000000";
String tmp = zero + Integer.toBinaryString(x);
return tmp.substring(tmp.length()-32);
}
}
// 결과
p =10 00000000000000000000000000001010
p =-11 11111111111111111111111111110101
p =-10 11111111111111111111111111110110
p =10 00000000000000000000000000001010
n =-10
~(n-1) = 10
5.2.3 쉬프트 연산자 << >>
- 이 연산자는 피연산자의 각 자리(2진수로 표현했을 때)를 ‘오른쪽(>>)’ 또는 ‘왼쪽(<<)’으로 이동(shift)한다고 해서 ‘쉬프트 연산자(shift operator)라고 부른다.
- [예제] 8 << 2 의 연산 과정
- 10진수 8은 2진수로 ‘00001000’
- ‘8 << 2’은 10진수 8의 2진수를 왼쪽으로 2자리 이동시킨다.
→ ‘00100000’ : 자리이동으로 인해 저장범위를 벗어난 값은 버려지고, 빈자리는 0으로 채워진다. - ‘8 << 2’의 결과는 2진수로 ‘00100000’이 된다. (10진수로 32)
- ‘<<’ 연산자의 경우, 피연산자의 부호에 상관없이 각 자리를 왼쪽으로 이동시키며 빈칸을 0으로 채움.
- ‘>>’ 연산자의 경우, 오른쪽으로 이동시키기 때문에 부호있는 정수는 부호를 유지하기 위해 왼쪽 피연산자가 음수인 경우 빈자리를 1로 채우고 양수인 경우 빈자리를 0으로 채운다.
- 쉬프트 연산자는 다른 이항연산자들과 달리 피연산자의 타입을 일치시킬 필요가 없기 때문에 우측 피연산자에는 산술변환이 적용되지 않는다.
- [예제] 쉬프트 연산의 예
public class _18_ShiftOperator {
// 10진 정수를 2진수로 변환하는 메서드
static String toBinaryString(int x) {
String zero = "00000000000000000000000000000000";
String tmp = zero + Integer.toBinaryString(x);
return tmp.substring(tmp.length()-32);
}
public static void main(String[] args) {
int dec = 8;
System.out.printf("%d >> %d = %4d \\t%s%n",
dec, 0, dec >> 0, toBinaryString(dec >> 0));
System.out.printf("%d >> %d = %4d \\t%s%n",
dec, 1, dec >> 1, toBinaryString(dec >> 1));
System.out.printf("%d >> %d = %4d \\t%s%n",
dec, 2, dec >> 2, toBinaryString(dec >> 2));
System.out.printf("%d << %d = %4d \\t%s%n",
dec, 0, dec << 0, toBinaryString(dec << 0));
System.out.printf("%d << %d = %4d \\t%s%n",
dec, 1, dec << 1, toBinaryString(dec << 1));
System.out.printf("%d << %d = %4d \\t%s%n",
dec, 2, dec << 2, toBinaryString(dec << 2));
System.out.println();
dec = - 8;
System.out.printf("%d >> %d = %4d \\t%s%n",
dec, 0, dec >> 0, toBinaryString(dec >> 0));
System.out.printf("%d >> %d = %4d \\t%s%n",
dec, 1, dec >> 1, toBinaryString(dec >> 1));
System.out.printf("%d >> %d = %4d \\t%s%n",
dec, 2, dec >> 2, toBinaryString(dec >> 2));
System.out.printf("%d << %d = %4d \\t%s%n",
dec, 0, dec << 0, toBinaryString(dec << 0));
System.out.printf("%d << %d = %4d \\t%s%n",
dec, 1, dec << 1, toBinaryString(dec << 1));
System.out.printf("%d << %d = %4d \\t%s%n",
dec, 2, dec << 2, toBinaryString(dec << 2));
System.out.println();
dec = 8;
System.out.printf("%d >> %2d = %4d \\t%s%n",
dec, 0, dec >> 0, toBinaryString(dec >> 0));
System.out.printf("%d >> %2d = %4d \\t%s%n",
dec, 32, dec >> 32, toBinaryString(dec >> 32));
}
}
// 결과
8 >> 0 = 8 00000000000000000000000000001000
8 >> 1 = 4 00000000000000000000000000000100
8 >> 2 = 2 00000000000000000000000000000010
8 << 0 = 8 00000000000000000000000000001000
8 << 1 = 16 00000000000000000000000000010000
8 << 2 = 32 00000000000000000000000000100000
-8 >> 0 = -8 11111111111111111111111111111000
-8 >> 1 = -4 11111111111111111111111111111100
-8 >> 2 = -2 11111111111111111111111111111110
-8 << 0 = -8 11111111111111111111111111111000
-8 << 1 = -16 11111111111111111111111111110000
-8 << 2 = -32 11111111111111111111111111100000
8 >> 0 = 8 00000000000000000000000000001000
8 >> 32 = 8 00000000000000000000000000001000
x << n 은 x * 2ⁿ의 결과와 같다.
x >> n 은 x / 2ⁿ의 결과와 같다.
- 곱셈이나 나눗셈 연산자가 있는데 굳이 쉬프트 연산자를 사용하는 이유?
→ 속도가 빠름, 그러나 실행속도도 중요하지만 프로그램을 개발할 때 코드의 가독성(readability)도 중요함.
→ 쉬프트 연산자보다는 곱셈 또는 나눗셈 연산자를 주로 사용, 보다 빠른 실행속도가 요구되어지는 곳만 쉬프트 연산자를 사용하는 것이 좋다. - [예제] 10진수, 16진수에 쉬프트 연산자 사용
public class _19_ShiftOperator2 {
public static void main(String[] args) {
int dec = 1234;
int hex = 0xABCD;
int mask = 0xF;
System.out.printf("hex=%X%n", hex); // hex=ABCD
System.out.printf("%X%n", hex & mask); //
hex = hex >> 4;
System.out.printf("%X%n", hex & mask);
hex = hex >> 4;
System.out.printf("%X%n", hex & mask);
hex = hex >> 4;
System.out.printf("%X%n", hex & mask);
}
}
// 결과
hex=ABCD
D
C
B
A
→ 쉬프트 연산자와 비트 ‘&’ 연산자를 이용해서 16진수를 끝에서부터 한자리씩 뽑아내는 예제
반응형
'Java > Java의 정석' 카테고리의 다른 글
[Java의 정석/3-1] 조건문 - if, switch (0) | 2023.03.15 |
---|---|
[Java의 정석/2-6] 그 외의 연산자 (0) | 2023.03.15 |
[Java의 정석/2-4] 비교 연산자 (0) | 2023.03.15 |
[Java의 정석/2-2,3] 단항 연산자와 산술 연산자 (0) | 2023.03.07 |
[Java의 정석/2-1] 연산자(Operator) (1) | 2023.03.05 |