💻 2진수와 친해질 수 있을까..? 아니 친해져야 한다
IT BASE

💻 2진수와 친해질 수 있을까..? 아니 친해져야 한다

🖱️ 진수 표기법에 대하여


우리가 어릴 때 부터 지금까지 접해왔던 숫자 표기법은 10진수이다.
하지만 프로그래밍 세계에서는 이와 별개로 3개의 표현법이 더 있다.

1

  • 10진수는 항상 우리가 쓰던 방식이다.
  • 8진수는 0~7까지는 10진수랑 같으며, 8이 되면 올림해서 10으로 표기한다.
  • 2진수 컴퓨터가 받아들이는 디지털 신호이다. (0과 1로 표기)
  • 16진수는 2진수를 쉽게 표현하기 위해서 4bit씩 나누어서 표기한다.
    (09까지는 10진수와 같으며, 10부터는 af로 표기)

🖱️ 값과 메모리


2

  1. 어떤 값이든 2진수로 표현할 수만 있다면
    전기적 신호와 자기적 신호로 바꿀 수 있다. (★★★★★)
    > RAM/HDD에 저장할 수 있다.
  2. 2진수로 바꾸기 위한 규칙이 필요하다. (4가지)
    2의보수법을 사용한다.

07_2진수의 메모리 전달

  • 전기적 신호와 자기적 신호가 오게 되면 바로 CPU에 가는 것이 아니다.
  • CPU에는 L1, L2, L3 캐시가 있다. (아직 깊게 공부하지는 못함)
  • HDD에서 CPU로 직접 명령어가 전달되지 못하며, RAM에 Loading되고 CPU의 L1캐시에 저장된다.

🖱️ RAM과 HDD에 어떻게 저장되는가


3

🖱️ 2진수의 값 표현 규칙(4가지)


  • Sign-Magnitude(부호 절대값)부호 절대값 방식은 가장 쉽게 생각할 수 있는 방식이다.
    최상위비트를 부호비트(0이면 양수, 1이면 음수)로 사용하고, 나머지는 절대값을 표현한다.

4

  • 위의 예를 보면 5-3을 수행하려고 한다.

    사람의 입장에서는 정말 쉽게 2라고 답변을 할 수 있지만, 안타깝게도 컴퓨터는 음수를 계산하지 못한다.
    위 방법은 대한 방법으로 나온것인데 몇가지 문제점들이 보인다.

  • - 0을 +0과 -0으로 나누기가 애매하다. - 계산한 값이 다르게 나온다.

5

  • 그에 대한 대안으로 나온 것이 1의 보수법, 2의보수법이다.1의 보수는 어떤 수를 더해서 1이 되게끔 보충해주는 수를 말한다.

  • 1의 1의 보수는 0이다.<br> 0의 1의 보수는 1이다.

  • 결론적으로 1의보수는 2진수로 바꾼 수를 역으로 뒤집으면 된다.

  • 하지만 아직도 값이 일치하지 못한다.2의 보수는 어떤 수를 더해서 2가 되게끔 보충해주는 수를 말한다.

    2의 보수는 1의 보수에서 +1을 더한 값이다.

  • 위의 방법으로 답을 구하면 정확하게 일치한다.

  • 참고로 8bit를 넘어가는 수는 버린다.

6

Excess-K는 K로 지정된 값을 무조건 더하는 방법이다. 음수던 양수던 상관하지 않는다.

🖱️ 부동소수점 계산 방법


08_부동소수점 계산법 1

  1. 정수와 소수점를 구별한다. (12와 .375)
  2. 정수는 2진수로 바꾸며 소수점 아래 숫자는 다음과 같은 규칙에 의해 2진수로 변환된다.
    • 소수점 이하 숫자 * 2 -> 정수 부분만 기록한다. (0,1,1)
    • 소수점 이하 숫자가 0 이거나 *2를 해서 무한 반복되면 stop한다.
  3. 2진수 정규화를 실시한다. (1100.011 -> 1.100011 * 2^3)
    • 가수부 * 2^n 으로 표시된다. (2진수이기 때문에 2의 거듭제곱으로 표현함)
    • 정수부분은 버린다.
    • 소수점 부분은 가수부라고 하며 2의 거듭제곱의 수를 지수부라고 한다.

09_부동소수점 계산법 2

  1. 지수부는 Excess-K 방식으로 계산하여 2진수로 바꾼다. (k = (2^n-1)-1)
    • 32bit에서 지수부는 8bit이므로 k = 2^7-1 = 127
    • 64bit에서 지수부는 11bit이므로 k = 2^10-1 = 1023
  2. 가수부는 Sign-Magnitude 방식으로 계산한다.
    • 가수부를 비트 처음부터 일렬로 나열한다.
  3. 16진수로 나타내려면 4bit씩 나눈다.

10_부동소수점 계산법 3

🖱️ 비트 연산자

  • 이미지 및 영상 처리에 사용된다.
    • 마스킹, 오버레이 기법에 사용된다.
    • 색조 변경에 사용된다.
    • R(1byte), G(1byte), B(1byte) / 0~255로 세기조절
 System.out.println(a & b);
    // a = 0000 0000 0000 0000 0000 0000 0110 1100
    // b = 0000 0000 0000 0000 0000 0000 0101 0101
    // --------------------------------------------
    //     0000 0000 0000 0000 0000 0000 0100 0100 = 68

    System.out.println(a | b);
    // a = 0000 0000 0000 0000 0000 0000 0110 1100
    // b = 0000 0000 0000 0000 0000 0000 0101 0101
    // --------------------------------------------
    //     0000 0000 0000 0000 0000 0000 0111 1101 = 125

    System.out.println(a ^ b);
    // a = 0000 0000 0000 0000 0000 0000 0110 1100
    // b = 0000 0000 0000 0000 0000 0000 0101 0101
    // --------------------------------------------
    //     0000 0000 0000 0000 0000 0000 0011 1001 = 57

    // 비트 연산에서 not은 ! 연산자가 아니라 ~ 연산자 이다.
    System.out.println(~a);
    // a = 0000 0000 0000 0000 0000 0000 0110 1100
    // --------------------------------------------
    //     1111 1111 1111 1111 1111 1111 1001 0011 = -109
  • 나머지 연산을 구할때도 활용된다.
    System.out.println(57 % 2);
    System.out.println(57 & 0b0000_0001);
    System.out.println(57 & 0x1); // 맨 끝의 1비트만 비교한다. (속도가 빠르다.)
    System.out.println(57 & 1);

    System.out.println(57 % 4);
    System.out.println(57 & 0b11);

    System.out.println(57 % 8);
    System.out.println(57 & 0b111); // 57 & 7

    System.out.println(57 % 16);
    System.out.println(57 & 0b1111); // 57 & 15 = 57 & 0xf

비트 이동 연산자 : >>, >>>, <<

  1. << 연산자의 비트 이동 => 'i^이동비트'를 곱한 것
    • 속도가 빠르다.
 int i = 1;
    //      [00000000000000000000000000000001] = 1

    System.out.println(i << 1);
    //     0[0000000000000000000000000000001 ]
    //      [00000000000000000000000000000010] = 2

    System.out.println(i << 2);
    //    00[000000000000000000000000000001  ]
    //      [00000000000000000000000000000100] = 4

    i = 11; // [00000000000000000000000000001011]
    System.out.println(i << 1); //   0[00000000000000000000000000010110] => 22
    System.out.println(i << 2); //  00[00000000000000000000000000101100] => 44
    System.out.println(i << 3); // 000[00000000000000000000000001011000] => 88
  1. >> 연산자의 비트 이동 => n / 2^이동비트
    • 나누기 연산을 수행하는 것 보다 계산 속도가 빠르다
 int i = 105; // [00000000000000000000000001101001]

    System.out.println(i); //                   => 105

    System.out.println(i >> 1);
    // [ 0000000000000000000000000110100]1
    // [00000000000000000000000000110100]       => 52

    System.out.println(i >> 2);
    // [  000000000000000000000000011010]01
    // [00000000000000000000000000011010]       => 26
  1. >>> 연산자 => 왼쪽 빈자리를 음수 양수 상관없이 무조건 0으로 채운다.
int i = 105; // [00000000000000000000000001101001]

    System.out.println(i); //                       => 105


    System.out.println(i >>> 1);
    // [ 0000000000000000000000000110100]1
    // [00000000000000000000000000110100]1          => 52

    System.out.println(i >>> 2);
    // [  000000000000000000000000011010]01
    // [00000000000000000000000000011010]01         => 26
  1. 특정 비트 값 추출하기
    • 비트연산자(>>) + 비트연산자(&)
int i = 0x27a130ff;
    int a, b, c, d;

    System.out.println(i);
    System.out.println(Integer.toHexString(i));


    // [00100111_10100001_00110000_11111111] => 27a130ff

    a = i >> 24;
    // [00000000_00000000_00000000_00100111]_10100001_00110000_11111111

    b = i >> 16 & 0xff;
    //  [00100111_10100001_00110000_11111111] => 27a130ff
    //  [00000000_00000000_00100111_10100001]_00110000_11111111
    //   00000000_00000000_00100111_10100001  => 0x000027a1
    // & 00000000_00000000_00000000_11111111  => 0x000000ff
    // --------------------------------------
    //   00000000_00000000_00000000_10100001

    System.out.println(Integer.toHexString(a));
    System.out.println(Integer.toHexString(b));
  1. 특정 비트 값 추출하기 2
    • 비트연산자(|) + 상수
    final int CSS           = 0x01; // 0000 0001
    final int HTML          = 0x02; // 0000 0010
    final int PHP           = 0x04; // 0000 0100
    final int PYTHON        = 0x08; // 0000 1000
    final int JAVASCRIPT    = 0x10; // 0001 0000
    final int JAVA          = 0x20; // 0010 0000
    final int CPP           = 0x40; // 0100 0000
    final int C             = 0x80; // 1000 0000

    // C, Java, Python, HTML 을 할 줄 아는 개발자의 정보를 설정하라!
    int lang = C | JAVA | PYTHON | HTML; // 10101010

    // 정수 값에서 특정 비트의 값만 검사하는 방법
    // 예) 10101010 (C, Java, Python, HTML)
    //
    // CPP 언어를 할 줄 아는지 검사하기
    //     10101010
    //   & 01000000 (조사하려는 값과 AND 한다. 01000000)
    //   ----------------------
    //     00000000
    //
    // AND 결과 값을 검사 값과 같은지 비교하면 된다.
    //     00000000 (결과값)
    //     01000000 (CPP 여부를 조사하는 값)
    // => 결과 값과 조사한 값이 같지 않으면 해당 비트가 0이라는 의미다.

    System.out.printf("CSS        : %b\n", (lang & CSS) == CSS);
    System.out.printf("HTML       : %b\n", (lang & HTML) == HTML);
    System.out.printf("PHP        : %b\n", (lang & PHP) == PHP);
    System.out.printf("Python     : %b\n", (lang & PYTHON) == PYTHON);
    System.out.printf("JavaScript : %b\n", (lang & JAVASCRIPT) == JAVASCRIPT);
    System.out.printf("Java       : %b\n", (lang & JAVA) == JAVA);
    System.out.printf("C++        : %b\n", (lang & CPP) == CPP);
    System.out.printf("C          : %b\n", (lang & C) == C);

    System.out.println("--------------------------");
    System.out.printf("CSS        : %b\n", (lang & CSS) > 0);
    System.out.printf("HTML       : %b\n", (lang & HTML) > 0);
    System.out.printf("PHP        : %b\n", (lang & PHP) > 0);
    System.out.printf("Python     : %b\n", (lang & PYTHON) > 0);
    System.out.printf("JavaScript : %b\n", (lang & JAVASCRIPT) > 0);
    System.out.printf("Java       : %b\n", (lang & JAVA) > 0);
    System.out.printf("C++        : %b\n", (lang & CPP) > 0);
    System.out.printf("C          : %b\n", (lang & C) > 0);


==============================================================================

CSS        : false
HTML       : true
PHP        : false
Python     : true
JavaScript : false
Java       : true
C++        : false
C          : true
--------------------------
CSS        : false
HTML       : true
PHP        : false
Python     : true
JavaScript : false
Java       : true
C++        : false
C          : true

🖱️ 저급 프로그래밍 언어


컴퓨터가 이해하기 쉽게 작성된 프로그래밍 언어로 일반적으로 기계어어셈블리어를 일컫는다.
실행속도가 매우 빠르지만 배우기가 어려우며 유지보수가 힘든 것이 단점이다.
현재는 특수한 경우가 아니면 사용되지 않는다. -위키백과-

기계어

8B542408 83FA0077 06B80000 0000C383
FA027706 B8010000 00C353BB 01000000
C9010000 008D0419 83FA0376 078BD98B
B84AEBF1 5BC3

어셈블리어

fib:
    mov edx, [esp+8]
    cmp edx, 0
    ja @f
    mov eax, 0
    ret

    @@:
    cmp edx, 2
    ja @f
    mov eax, 1
    ret

    @@:
    push ebx
    mov ebx, 1
    mov ecx, 1

    @@:
        lea eax, [ebx+ecx]
        cmp edx, 3
        jbe @f
        mov ebx, ecx
        mov ecx, eax
        dec edx
    jmp @b

    @@:
    pop ebx
    ret

🖱️ 결론

  • 어떤 값이든 2진수로 표현할 수만 있다면 전기적 신호와 자기적 신호로 바꿀 수 있다.
  • 내가 원하는 파일을 실행시키기 위하여 내부적으로 많은 과정들을 거친다.
  • 1번과 4번의 방법은 부동소수점을 2진수로 표현할 때 지수부를 이 규칙에 따라 표현한다.
  • 현대의 대부분의 컴퓨터는 2의보수를 음수 표현 방법으로 사용한다.
  • 부동소수점은 지수부와 가수부로 나누어서 계산하며 32bit와 64bit에 따라 다른 결과가 나온다.
  • 저급 프로그래밍 언어를 보면서 현재 나온 웹 프로그래밍의 언어에 대한 감사함이 들었다.

'IT BASE' 카테고리의 다른 글

📝 클래스 다이어그램 (Class Diagram)  (0) 2021.08.03
⌨️ Compile & OS  (0) 2021.07.18