
이진수가 특히 좋은 점 이진수로 굉장히 많은 꼼수가 가능한 이유는 간단하기 때문이다.
한자리 숫자가 0,1이기 때문에 굉장히 재미있는 걸 많이 할 수 있다.
비트 연산
여기의 코드가 한 줄 있다.
int a;
이 번수 a에 어떤 값이 들어 있는지 모른다.
이 변수와 비트 연산만 이용해서 변수의 값을 0으로 초기화할 수 있을까?
어차피 비트 연산은 몇개 없으니 다 해보면된다.
모르면 일단 해보면서 보고 그 관찰한 결과가 왜 나오는지 고민하면 된다.
변수 a의 하위 8비트의 값이 '0101 1010'이라 가정한다.
어떤 비트 연산을 하면 a의 값이 0이 될까?
a = a ? a;
xor 같은 숫자 면 모두 0이 된다.
일반적으로 a = 0 보다 a = a ^ a이 성능이 더 빠르다.
성능이 중요한 임베디드 시스템에서 자주 쓰던 꼼수
아직도 똑똑한 컴파일러는 XOR 연산으로 바꿔주기도 함.
a = 0를 보는 순간 a = a ^ a로 바꾼다는 의미이다.
여기에 두 정수가 있다.
int a = 3;
int b = 112;
한 가지 비트 연산자를 세 번 쓰면 서로의 값을 바꿀 수 있다.
과연 어떤 연산자 일까?
스왑같은개념이라고 보면된다.
a = a ^ b;
b = a ^ b;
a = a ^ b;
정답은 XOR
촉으로도 가능한데
NOT은 하나만 받기 때문에 패스
두 변수를 아무리 AND / OR 해봐야 값이 변하지 않음
하나 남은 것 XOR 밖에 없다.
비트마스킹

if (num % 2 == 0) //짝수
if (num % 2 == 1) //홀수
if (num % 2 != 0) //홀수 좀더 나은방법
홀수 더 좋은 방법은
컴퓨터에서 0이랑 비교할 수 있으면 비교하는 게 무조건 좋다.
비트 연산으로 짝수/홀수 판별하기
if((num & 0x1) == 0) //짝수
if((num & 0x1) != 0) //홀수
위의 값이 뭐든 간에 0x1을 해서 0인지 1인지 알 수 있다.
앞에 0으로 세팅을 해놨기 때문에 앞에는 모두 0으로 들어온다.
이걸 마스킹이라고 한다. 즉 앞에는 0으로 다 가렸다.
이렇듯 필요한 피트만 추출하는 방식 비트 마스킹이라고 한다.
mask : 가리다, 가면
비트플래그
불리언 형의 1,0을 flag라고 한다.
이런 걸 여러 개 모아놓을 수 있다.
불리언 하나면 4바이트씩 먹는다. 근데 0, 1만 있으면서 왜 4바이트씩이나 먹냐?
1비트 형 자료형은 없으니깐 8개를 모아서 1바이트로 쓴다.
32개를 모아서 int형으로 써줄게 그러면 int형 하나에 32개의 불리언을 쓸 수가 있다.
32개 변수를 쓰는 것보다 용량이 작다는 장점이 있다.
특정 플래그를 켜는 방법
플래그 = 플래그 | 마스크;
기존의 비트는 다 유지되면서 켜려는 or을 통해서 1이 되게 만들어준다.
특정 플래그를 끄는 방법
플래그 = 플래그 & ~마스크;
특정 플래그를 토글 하는 방법
플래그 = 플래그 ^ 마스크;
토글이란 켜진 상태(on) 라면 끄고(off)
꺼진 상태(off) 라면 켜는(on) 행위
비트 플래그 예
final byte ATTACK_NONE = 0;
final byte ATTACK_FIRE = 1;
final byte ATTACK_ICE = 2;
final byte ATTACK_WIND = 3;
final byte ATTACK_ARCANE = 4;
final byte ATTACK_SIZE = 5;
byte propertyFlags = 8; //외부에서 받은값
System.out.printf("0%s\n", Integer.toBinaryString(propertyFlags));
byte mask1 = (byte) ((1 << ATTACK_FIRE) | (1 << ATTACK_ARCANE));
propertyFlags |= mask1; //화속성, 비전속성 켬
System.out.println(Integer.toBinaryString(propertyFlags));
byte mask2 = (byte) (1 << ATTACK_ICE);
propertyFlags ^= mask2; // 빙속성 토글
System.out.println(Integer.toBinaryString(propertyFlags));
byte mask3 = (byte) (1 << ATTACK_WIND);
propertyFlags &= (byte) ~mask3; // 풍속성 끔
System.out.println(Integer.toBinaryString(propertyFlags));
결과

사진 설명을 입력하세요.
비트 마스킹 대소문자 변환
char c = 98;
char mask1 = 0x20;
if (c >= 'a' && c <= 'z') {
c = (char) (c ^ mask1);
}
다른 방식의 비트 마스킹 대소문자 변환방법
static void BitMasking(){
char c1 = 'A';
if(isAlphabet(c1)){
c1 = (char) (c1 | mask1);
}
if(isAlphabet(c1)){
c1 = (char) (c1 &~ mask1);
}
}
static boolean isAlphabet(char alphabet){
return Pattern.matches("^[a-zA-Z]*$",Character.toString(alphabet));
}
비트 마스킹 2의 승수 판별하기
어떤 수가 2의 승수인지를 어떻게 판단할까?
2의 승수는 2로만 계속 곱한 수
static boolean isPower(int n){
while (n != 1) {
if (n % 2 != 0) {
return false;
}
n = n / 2;
}
return true;
}
계속 2로 나눠서 나머지가 0이 아니면 2의 승수가 아니다.
byte a = 0b1010;
if(a == (a & -a)){
System.out.println("2의 거듭제곱이다.");
}else{
System.out.println("2의 거듭제곱이 아니다.");
}
a를 2의 보수를 하게 되면 -a가 된다.
그리고 a & -a를 하게 되면 2의 거듭제곱은 a와 동일하다.
1000 > 0111 + 1 > 1000 == 1000
하지만 2의 거듭제곱을 하지 않은 수는 동일하지 않다.
1010 > 0101 + 1 > 0110 != 1010
'이전자료 > 웹개발' 카테고리의 다른 글
node.js(express) .env로 DB정보 따로 관리하기 (0) | 2022.01.17 |
---|---|
프로그래밍에서 논리란? (0) | 2022.01.17 |
웹개발을 위한 XAMPP 설치 방법 [PHP 코딩 서버 아파치] (0) | 2022.01.17 |
구글 크롬 플래시중단, 플래시대체 파일 업로드 테스트 방법 (0) | 2022.01.17 |
웹개발을 위한 XAMPP 설치 방법 [PHP 코딩 서버 아파치] (0) | 2021.08.15 |