상세 컨텐츠

본문 제목

Bit 연산 Leaning Test

IT/프로그래밍

by James Lee. 2015. 12. 6. 19:51

본문

Bit연산에 대한 학습 테스트 작성

Bit연산의 종류와 그 의미는 아래의 표와 같다.


부호
의미
|OR
&AND
^XOR
~NOT
<<

LeftShift

>>RightShift
>>>

RightShiftFillZero


& 연산

& (AND)연산은 비교대상이 전부 1이면 1, 아니면 0을 반환한다.


비교 대상은 2진수와 비교하기 무난한 16진수를 이용하여 표현하였다.

0x110 & 0x10

0x110 & 0x010 (0x10 == 0x010)

0x110

0x010

결과

0x010



0x101

0x010 (모든 자릿수가 서로 다르다)

0x000 (따라서 결과값은 왼쪽과 같다)


0x010

0x111 (2번째 자릿수가 서로 같다)

0x010 (결과값)

@Test
public void bitWiseAnd() {
    assertEquals(0x010, 0x110 & 0x10);
    assertEquals(0x000, 0x101 & 0x010);
    assertEquals(0x010, 0x111 & 0x010);
}


|연산 

| (OR)연산은 비교대상 중 하나만 1이어도 결과값을 1로 반환한다.


0x1001

0x0011 ( 앞에서 2번째만 전부 0이고, 나머지는 1이 포함되어 있다)

0x1011 ( 결과값)


0x0001

0x0011 (0x11)

0x0011 (결과값)


0x0001

0x0110(0x110)

0x0111(결과값)


@Test
public void bitWiseOr() {
    assertEquals(0x1011, 0x1001 | 0x0011);
    assertEquals(0x0011, 0x0001 | 0x11);
    assertEquals(0x0111, 0x0001 | 0x110);
}


^연산

^(XOR)연산은 연산 대상이 서로 다르면 1, 같으면 0을 반환한다.

연산대상이 3개 이상일때는 1의 개수가 홀수이면 1, 짝수이면 0을 반환한다.

왜 그런가?

1^0^1^0^1을 예로 들어보자

1^0 -> 1

1^1^0^1이 된다.

1^1->0

0^0^1이 된다.

0^0->0

0^1이 된다.

0^1 -> 1

1을 반환한다.


0x101

0x010 (세 자리가 전부 다르다)

0x111 (결과값)


0x110011

0x110011 (모든 자리가 전부 같다)

0x000000 (결과값)


0x11001

0x10101 (앞에서 2, 3번째 자리가 다르다)

0x01100 (결과값)



@Test
public void bitWiseXor() {
    assertEquals(0x111, 0x101 ^ 0x010);
    assertEquals(0x000000, 0x110011 ^ 0x110011);
    assertEquals(0x01100, 0x11001 ^ 0x10101);
}


<<연산

<<(Left Shift)연산은 대상값을 2진수로 표현한 다음, <<다음에 오는 값만큼 왼쪽으로 Shift 연산 하는 것이다.

예를들어 5<< 3은 2진수 101 << 3으로 표현된다.

이 식은 이진수 101을 왼쪽으로 3번 Shift 연산하라는 말이고

101을 왼쪽으로 3번 이동시키면 101000이 된다(옮겨진 빈 자리는 0으로 채워진다)


16진수는 2진수로 표현하기가 쉽기 때문에 10진수보다는 LeftShift연산으로 표현하기가 쉽다.

예를들어 1111 0000 1111을 4번 Left Shift  연산을 한다고 가정한다.

그러면 결과값이 1111 0000 1111 0000이 나온다.


이것을 16진수로 표현하면 0x101 << 4 == 0x1010이 된다.

16진수는 2진수로 표현하면 4배의 공간을 차지하기 때문에 16진수 1칸을 Shift하려면 2진수 기준 LeftShift에 4배를 곱해야 한다.

(만약 32진수가 있다면, 5칸을 차지하기 때문에 32진수 1칸을 Shift하려면 <<5, 2칸을 Shift하려면 <<10을 해야 할 것이다..)


0x1101 << 8 (16진수일 경우 LeftShift 4가 1칸이므로 <<8은 2칸을 움직이면 된다.)

0x11010 (결과값)



@Test
public void bitWiseLeftShift() {
    assertEquals(40, 5 << 3);
    assertEquals(0x1010, 0x101 << 4);
    assertEquals(0x110100, 0x1101 << 8);
    assertEquals(0x1101000, 0x1101 << 12);
}


>> 연산

>>(Right Shift)는 <<의 반대 기능을 한다.

<<가 나누기 역활을 한다면 <<은 곱하기 역할이라고 볼 수 있다.


@Test
public void bitWiseRightShift() {
    assertEquals(0x1101, 0x11010 >> 4);
    assertEquals(0x1101, 0x110100 >> 8);
    assertEquals(0x1101, 0x1101000 >> 12);
}



>>>연산

>>>(RightShiftFillZero)는 >>연산과 비슷하지만 차이점이 있다.

RightShift를 하면서 생기는 기존 값의 왼쪽에 생기는 공백을 0으로 채운다는 점이다. 

이것이 실제 값으로는 어떤 차이가 있을까?

>>는 산술연산이지만, >>>는 논리연산으로 볼 수 있다.

>>>는 해당 값을 완전히 비트로 처리하기 때문이다.

이게 무슨 말일까?


예를들어 10에 >>>1연산과 >>1연산을 해보겠다.

10은 2진수로 1010이다.

1010에 >>1을 하면 101이 된다.

1010에 >>>1을 하면 101이고 이동한 만큼 왼쪽에 0을 채우므로 0101이 된다.

하지만 0101과 101은 같으므로 실제 값의 차이는 없다.

왜 그럴까?

양수는 왼쪽의 값에 0000000이 채워져 있다.

101도 사실 0000000000101과 같다.

이렇듯 기본적으로 양수는 왼쪽에 0이 채워져 있기 때문에, 이동한 만큼 값에 0을 채워줘도 실제 값에는 차이가 없는 것이다.

@Test
public void bitWiseRightShiftFillZero() {// >>>
    assertEquals(5, 10 >>> 1);
    assertEquals(5, 10 >> 1);
}



하지만 음수의 경우는 어떨까?


@Test
public void bitWiseRightShiftFillZero() {
    assertEquals(5, 10 >>> 1);
    assertEquals(5, 10 >> 1);
    assertEquals(-5, -10 >> 1);
    assertEquals(2147483643, -10 >>> 1);
}


값이 엄청나게 차이나는것을 확인할 수 있다.

왜 그럴까?

음수는 기본적으로 값의 왼쪽에 1이 채워진다.

따라서 -10은    1111111111111111111 10으로 표현된다.

이때 >>1연산은 1111111111111 1이 된다.

하지만 >>>1 연산은 (0)1111111111111 1이 된다. (왼쪽에 옮긴 만큼 0을 채우기 때문에)

따라서 실제로는 0111111111111111의 값인 2147483643이 나오게 되는 것이다.

~연산

~연산은 Bit Not 연산이다.

값을 반전시키는 연산이다. 1일때, 0을 반환하고 0일때, 1을 반환한다.

예를들어 105를 ~연산하면 어떤 값이 나올까?

105는 2진수로 표현하면 01101001이다. 

~연산이 적용되어 값이 반전되면 10010110이 된다.

값을 반전시키는 연산을 1의 보수라고 부른다.

하지만 1의 보수는 0에 보수를 취하면 0이 11111111 과 00000000 두가지로 표현 될 수 있다.

이러한 문제를 해결하기 위해 2의 보수법을 사용한다. 2의 보수란 1의 보수의 결과값에 1을 더해주는 연산법이다.

따라서 1의 보수로 나온 결과값 10010110에 1을 더해주는 2의 보수를 적용시키면 

10010111 (-105)이 나온다.

그렇다면 -106 (10010110)은 어떻게 나오는 것일까?


~연산은

그냥 1의 보수만 취해주는 것 같다. (+1 안해줌)

그래서 10010110이 나오고, 이것을 해석하면 -106이 나오는것


아하, 2의 보수법은

현재의 값을 음수로 값손실 없이 보존시키는 것..

105를 1의 보수로 변환시키면 -106이 나오지만 (부호 바뀌고 값도 달라짐)

105를 2의 보수로 변환시키면 -105가 나온다 (부호만 바뀜)


음수의 값을 확인하려면? 

음수값에 2의 보수법을 취해주면 된다 (부호만 바뀌므로)

10010111 (-105)에 2의 보수를 취해보자

01101001 이 나온다. (105)


@Test
public void bitWiseNot() {
    assertEquals(-106, ~105);
}



 


'IT > 프로그래밍' 카테고리의 다른 글

[Cucumber] 최종 정리 (Mental Model)  (0) 2015.12.06
[Cucumber] 작동원리 분석  (0) 2015.12.06
[TDD] 시침과 분침 사이 각도 계산  (0) 2015.12.06
[TDD] 이진 검색  (0) 2015.12.06
웹 프로토콜 동작 원리  (0) 2015.12.06

관련글 더보기

댓글 영역