컴퓨터 내부의 언어 체계

halang·2022년 10월 9일
5
post-thumbnail

개요

한 권으로 읽는 컴퓨터 구조와 프로그래밍 책을 정리한 내용입니다. 이번 포스팅에서는 1장 컴퓨터 내부의 언어 체계 - 컴퓨터는 어떤 말을 사용할까에 대해 설명드리겠습니다.


언어란 무엇인가

언어는 의사소통을 하기 위한 수단으로 복잡한 개념을 전달할 수 있습니다. 언어가 가지고 있는 뜻은 기호의 집합으로 인코딩됩니다. 하지만 의사소통이 제대로 되려면 당사자들이 모두 같은 문맥을 공유하여 같은 기호에 같은 뜻을 부여할 수 있어야 합니다.


문자 언어

문자 언어는 기호를 나열한 것입니다. 기호들을 정해진 순서대로 나열하면 단어가 만들어집니다. 예를 들어, 음식이라는 단어는 여섯 가지 기호로 이뤄지며 왼쪽부터 오른쪽 음절 순으로 초, 중, 종성을 적으면 'ㅇ', 'ㅡ', 'ㅁ', 'ㅅ', 'ㅣ', 'ㄱ'입니다. 영어도 같은 방식으로 food라는 단어는 'f', 'o', 'o', 'd' 글자로 이뤄집니다.

이처럼 문자 언어는 다음 세 가지 구성요소로 틀을 이룹니다.

  1. 기호가 들어갈 상자
  2. 상자에 들어갈 기호
  3. 상자의 순서

이는 컴퓨터 언어에서도 마찬가지입니다.


비트

우선 상자에 대해 생각해봅시다. 자연어에서는 상자를 문자라고 부르고 컴퓨터에서는 비트(bit) 라고 부릅니다. 비트라는 단어는 2진법을 사용한다는 뜻의 binary와 숫자를 뜻하는 digit가 합쳐진 말입니다. binary는 두 가지 부분으로 이뤄진 어떤 대상을 뜻하며 digit은 10진수를 표현하는 10가지 기호(0~9)를 뜻합니다.
비트는 2진법을 사용합니다. 이 상자에는 두 가지 기호 중 하나만 담을 수 있습니다. 있다라는 의미의 1과 없다라는 의미를 뜻하는 0이 이 상자에 들어갈 수 있는 유일한 기호가 됩니다.


논리 연산

논리 연산은 참, 거짓 두 가지 원소만 존재하는 집합에서의 연산입니다. '졸업식 장소는 어디인가요?' 와 같은 질문은 예/아니오로 답할 수 없기 때문에 한 비트만으로 표현할 수 없습니다. 반면, '밖에 비가 오나요?', '오늘 학교에 가나요?'와 같은 질문은 예/아니오로 답할 수 있습니다. 이와 같은 질문들을 엮어서 한 문장으로 만들 수도 있습니다. '밖에 비가 오거나 눈이 오면 우산을 사세요.', '오늘이 주말이고 학원에 안간다면 놀이공원에 가요'와 같은 문장들이 이에 해당됩니다.

또한 이 문장들을 아래와 같이 조금 다르게 표현할수도 있습니다.

'밖에 비가 오는가?'가 참이거나 '밖에 눈이 오는가?'가 참이면 '우산을 산다'가 참이다.
'오늘이 주말인가?'가 참이고 '오늘 학원에 안간다'가 참이라면 '놀이공원에 간다'가 참이다.

이렇게 다른 비트들이 표현하는 내용으로부터 새로운 비트를 만들어내는 동작을 논리 연산이라고 합니다.


불리언 대수

비트에 대해 사용할 수 있는 연산 규칙의 집합을 불리언 대수라고 합니다. 1800년대 영국 수학자 조지 불이 만들었으며 일반 대수와 마찬가지로 결합 법칙, 교환 법칙, 분배 법칙을 불리언 대수에 적용할 수 있습니다.

기본적인 불리언 대수
1. NOT : 논리적 반대를 의미합니다. 거짓인 비트에 NOT을 하면 참이 됩니다.
2. AND : 둘 이상의 비트에 작용합니다. 첫번째 비트가 참이고 두번째 비트가 참인 경우에만 결과가 참이 됩니다.
3. OR : 둘 이상의 비트에 작용합니다. 모든 비트가 거짓인 경우를 제외하고 항상 참이 됩니다.
4. XOR :첫번째 비트와 두번째 비트가 다른 값인 경우에만 참이 됩니다.

위 사진은 분리언 연산을 진리표라는 틀을 사용해 시각적으로 보여줍니다. 입력값은 박스의 밖에, 출력값은 박스 안에 있습니다. 이 표에서 T는 참을 뜻하고 F는 거짓을 뜻합니다. 예를들어, OR 연산에서 input값이 F, F일 경우 출력값이 F가 된다. 즉, False OR False = False 라는 의미이다.


드모르간의 법칙

드모르간의 법칙은 앞에서 봤던 법칙 이외에 불리언 대수에 적용할 수 있는 또다른 법칙으로 1800년대 영국 수학자인 오거스터스 드모르간이 알아냈습니다. 이 법칙은 a AND b라는 연산은 NOT(NOT a OR NOT b)와 같다고 말합니다. 이를 진리표로 나타내면 아래와 같습니다.

a AND b와 NOT(NOT a OR NOT b)연산의 결과가 같다는 사실을 확인할 수 있습니다. 이 말은 NOT을 충분히 사용하면 AND 연산을 OR 연산으로 대신할 수 있다는 뜻이므로 유용할 때가 종종 있습니다.


정수를 비트로 표현하는 방법

양의 정수 표현

우리는 보통 10진수 체계를 사용합니다. 10진수 체계에서는 10가지 기호인 숫자(digit)를 상자에 담을 수 있습니다. 상자는 오른쪽에서 왼쪽으로 쌓여가며 각 상자마다 일의 자리, 십의 자리, 백의 자리라는 이름이 붙습니다. 각 이름은 10의 거듭제곱에 해당합니다. 10010^0은 1, 10110^1은 10, 10210^2은 100 입니다. 이 체계는 지수를 적용할 밑을 10으로 사용합니다.

비트를 사용해 값을 만들 때도 비슷하게 접근할 수 있습니다. 10진 숫자가 아닌 비트를 사용하기 때문에 각 상자에 사용할 수 있는 기호는 앞서 말했다시피 1과 0 두가지 뿐입니다. 따라서 2진수에서는 1보다 큰 수를 표현하려면 새로운 상자를 추가해야 합니다. 가장 오른쪽에 있는 상자가 1의 자리라면 그 왼쪽에 있는 상자는 2의 자리가 될 것입니다. 2진수에서는 기호가 2개이기 때문에 각 상자는 자신의 오른쪽에 있는 상자의 자릿수에 2를 곱한 값의 자리를 표현하게 됩니다. 이렇듯 2진수는 밑을 2로 하는 수 체계입니다.

2진수에서 가장 오른쪽의 비트를 가장 작은 유효 비트(LSB)라고 부르고 가장 왼쪽의 비트를 가장 큰 유효 비트(MSB)라고 부릅니다. 가장 오른쪽의 비트를 변경하면 2진수의 값이 가장 작게 변경되고 가장 왼쪽의 비트를 변경하면 가장 크게 변하기 때문입니다.

2진수 덧셈

2진수 덧셈은 10진 덧셈과 비슷합니다. 각 비트를 LSB에서 MSB쪽으로 더하며 결과가 1보다 크면 1을 다음 자리(왼쪽)로 올립니다. 만약 덧셈 결과가 우리가 사용할 비트의 개수로 표현할 수 있는 범위를 벗어나면 어떻게 해야 할까요? 이런 경우에는 오버플로가 발생합니다. 오버플로란 말은 MSB에서 올림이 발생했다는 뜻입니다. 컴퓨터에는 조건 코드 레지스터라는 것이 있는데 이 정보 중에서 오버플로 비트를 담는 공간이 있습니다. 따라서 이 비트값을 보면 오버플로가 발생했는지 알 수 있게 됩니다.

음수 표현

부호와 크기

이번에는 비트로 음수를 표현하는 방법을 알아봅시다. 지금까지 배운 내용을 보면 4비트로 0부터 15까지 총 16가지의 수를 표현할 수 있었습니다. 음수와 양수를 구별하기 위해 흔히 부호를 사용합니다. 부호에는 양수를 의미하는 +와 음수를 의미하는 - 두가지가 있습니다. 따라서 우리는 이를 비트로 표현할 수 있습니다. 가장 왼쪽 비트(MSB)를 부호에 사용하면 4비트 중 3비트가 남아 총 15가지 음수와 양수를 표현할 수 있습니다. 1000 = -0 = 0000 = +0 이므로 16가지가 아닌 15가지라는 점을 유의해 주시면 됩니다.
한 비트를 부호에 사용하고 나머지 비트를 수의 크기로 사용하는 방법을 부호와 크기(sign and magnitude) 표현법이라고 말합니다.
부호와 크기 표현법은 두 가지 단점이 있습니다.

  1. 0을 표현하는 방법이 두 가지 -> 비트 구성하는데 드는 비용 낭비
  2. XOR과 AND를 통한 덧셈 계산 사용 불가

예를 들어, +1과 -1을 더해봅시다. 원래 값은 0이 나와야 하는데 부호와 크기 표현법으로 이를 계산하면 -2의 결과가 나옵니다.


1의 보수

음수를 표현하는 또 다른 방법으로 양수의 모든 비트를 뒤집는 방법이 있습니다. 이런 방법을 1의 보수 표현법이라고 합니다. 이 방법에서도 비트들을 부호 비트와 나머지로 나눕니다. 그리고 NOT 연산을 통해 보수를 얻습니다.

예를 들어, 0111(+7)의 각 비트를 토글하면 1000(-7)을 얻을 수 있습니다.

하지만 해당 표현법에서도 아래와 같은 단점이 있습니다.

  1. 0을 표현하는 방법이 두 가지 -> 비트 구성하는데 드는 비용 낭비
  2. XOR과 AND를 통한 덧셈 계산을 하려면 순환 올림을 해야함 -> 이를 처리하기 위한 하드웨어 추가 (비용 더 듬)

순환 올림에 대해 좀 더 설명드리겠습니다. 1의 보수로 덧셈을 하려면 MSG 쪽에서 올림이 발생한 경우 LSB로 올림을 전달하여 다시 한번 계산해야 합니다. 이를 순환 올림이라고 하는데 이를 처리하기 위한 하드웨어가 추가로 필요합니다.

2의 보수

앞서 봤던 두 표현법의 단점을 해결해주는 표현법이 바로 2의 보수 표현법입니다. 어떤 수의 비트를 뒤집고(각 비트의 NOT을 취하고) 1을 더해주면 음수를 얻을 수 있습니다. 이때 MSB에서 올림이 발생할 경우 해당 값은 버립니다.

+0을 의미하는 0000을 뒤집으면 1111이 됩니다. 여기서 1을 더해주면 10000인데 올림은 버리므로 0000이 됩니다. 따라서 2의 보수 표현법에서는 0을 표현하는 방법이 하나뿐입니다.

실수를 표현하는 방법

이제는 2진 소수점을 표현할 방법에 대해 알아봅시다.

고정소수점 표현

2진수로 소수를 표현하기 위해 소수점의 위치를 임의로 고정시키는 방법을 고정소수점 표현법이라고 합니다. 예를 들어 4비트가 있다면 그중 2비트는 2진 소수점의 오른쪽에 있는 분수들을 표혆나ㅡㄴ데 쓰고 나머진 왼쪽에 있는 숫자들을 표현하는 데 쓴다고 해봅시다. 소수점을 기준으로 각각 왼쪽과 오른쪽에서 네 가지 값을 표현할 수 있습니다.
하지만 이러한 방식은 쓸모 있는 범위의 실숫값을 표현하기 위해 필요한 비트 수가 너무 많습니다. 일부 고정소수점 수가 응용하기에 유용한 경우가 있지만 일반적으로는 모든 수를 표현하기에 메모리 비용이 너무 많이 들기 때문에 다른 방법이 필요합니다.

부동소수점 표현

부동소수점 표현법에서는 과학적 표기법을 2진수에 적용합니다. 따라서 가수 부분(소수점 왼쪽이 한 자리)은 2진 소수로, 지수 부분은 2의 거듭제곱 횟수를 표현합니다. 가수가 같다고 해도 지수가 무엇인가에 따라 소수점 왼쪽 숫자의 자리가 달라지기 때문에 결국 소수점의 위치가 정해져 있지 않다라고 생각할 수 있습니다. 따라서 부동소수점 표현법이라고 불립니다.
하지만 부동소수점 표현법에는 몇가지 비효율적인 부분이 있습니다.

  1. 비트 조합 중에 낭비되는 부분이 많다.
  2. 비트 패턴이 가능한 모든 수를 표현하지 못한다.

IEEE 부동소수점 수 표준

부동소수점 수 시스템은 컴퓨터에서 계산을 수행할 때 실수를 표현하는 표준 방법입니다. 더 많은 비트를 사용하며 가수와 지수에 대해 각각 부호 비트를 사용합니다. 다만 지수에 대한 부호 비트는 지수의 비트 패턴에 감춰져 있습니다. 또한 낭비되는 비트 조합을 최소화하고 반올림을 쉽게 하기 위한 여러 트릭이 사용됩니다.
정밀도를 높이기 위해 사용하는 트릭중 하나는 정규화입니다. 정규화는 가수를 조정해서 맨 앞(왼쪽)에 0이 없게 만드는 방법 입니다. 이렇게 가수를 조정하려면 지수도 조정해야 합니다.
두번째 트릭은 가수의 맨 왼쪽 비트가 1이라는 사실을 알고 있으므로 이를 생략하는 방법입니다. 이로 인해 가수에 1비트를 더 사용할 수 있게 됩니다.

두 가지 부동소수점 수가 자주 쓰이는데 한가지는 기본 정밀도 부동소수점 수이고 다른 하나는 2배 정밀도 부동소수점 수입니다. 기본 정밀도 수는 32비트를 사용하며 2배 정밀도 수는 64비트를 사용하기 때문에 더 넓은 범위를 표현할 수 있습니다.

그림 1-13

두 형태 모두 가수에 대한 부호를 사용합니다. 위 그림에서 보이는 S가 바로 이 부호입니다. 반면 지수에 대한 부호 비트는 따로 없습니다. 이를 편향된 지숫값을 사용하여 127(01111111)이 지수 0을 표현하고 1(00000001)이 지수 -126을 표현하도록 하였습니다.

2진 코드화한 10진수 시스템

2진수로 수를 표현하는 다른 방식이 있습니다. 그 중 2진 코드화한 1진수(BCD)에 대해 알아봅시다. BCD는 4비트를 이용해 10진 숫자 하나를 표현합니다. 12를 2진수로 표현하면 1100이지만 BCD로 표현하면 0001 0010입니다. 하지만 BCD는 2진수를 효율적으로 활용하지 못합니다. 일반적인 2진수에 비해 더 많은 비트를 사용하기 때문입니다.

2진수를 다루는 쉬운 방법

2진수를 더 읽기 쉽게 표현하는 방법을 배워봅시다.

8진 표현법

그림 1-14
8진 표현법은 2진수 비트들을 3개씩 그룹으로 묶는 아이디어입니다.

16진 표현법

컴퓨터 내부가 8비트의 배수를 사용해 만들어지고 있어서 16진법 표현법을 주로 사용합니다. 8의 배수는 16진수 한 자리의 비트 수인 4로 나눠지지만 8진수 한 자리의 비트 수인 3으로는 균일하게 나눠지지 않기 때문입니다. 10부터 15까지의 수는 a~f 기호로 표현합니다.
16진 표현법은 2진수 비트들을 4개씩 그룹으로 묶습니다.

그림 1-15

프로그래밍 언어의 진법 표기법

보통 수학책에서는 아래 첨자를 사용해 각 진법을 구분합니다. 하지만 아래 첨자는 키보드로 입력하기 불편합니다. 따라서 여러 프로그래밍 언어에서는 다음과 같은 표기법을 따릅니다.

8진 숫자 : 0으로 시작, ex) 017
10진 숫자 : 1부터 9 사이의 숫자로 시작하는 숫자, ex) 123
16진 숫자 : 0x가 접두사로 붙은 숫자, ex) 0x12f


비트 그룹의 이름

컴퓨터를 설계하는 사람은 비용을 고려해 컴퓨터가 사용할 비트의 개수와 비트들의 조직을 결정합니다. 비트의 개수와 조직에 대해 여러 아이디어가 있었지만 그중 일부만 살아남았습니다. 비트는 너무 작아서 기본 단위로 사용하기에는 유용성이 떨어집니다. 따라서 비트를 좀 더 큰 덩어리로 조직화해야 합니다. 시간이 지남에 따라 8비트 덩어리가 기본 단위로 널리 쓰이기 시작했고 이를 바이트(byte)라고 부릅니다.
표 1-10
위 표는 비트의 묶음을 부르는 이름입니다. 워드(word)는 컴퓨터가 설계상 자연스럽게 사용할 수 있는 비트 묶음의 크기를 가리키는 말로 쓰입니다. 자연스럽게 쓸 수 있다는 말은 컴퓨터가 빠르게 처리할 수 있는 가장 큰 덩어리를 뜻합니다.


텍스트 표현

이제 수를 사용해 문자나 키보드에 있는 다른 기호 등을 표현하는 방법을 알아봅시다.

아스키 코드

텍스트를 표현하는 방법으로 미국 표준 코드(ASCII)를 사용하고 있습니다. 아스키는 키보드에 있는 모든 기호에 대해 7비트 수 값을 할당했습니다.
표 1-11

다른 표준의 진화

컴퓨터가 널리 쓰이게 됨에 따라 다른 언어를 지원할 필요가 많아졌습니다. 국제 표준화 기구인 ISO에서 ISO-646과 ISO-8859를 도입했습니다. 이 외에도 일본어, 중국어, 아랍어, 한국어 등의 표준도 생겼습니다. 시간이 지나 비트 가격이 떨어지면서 유니코드 라는 새로운 표준이 만들어졌고 문자에 16비트 코드를 부여했습니다. 그 후 유니코드는 21비트까지 확장됐습니다.

유니코드 변환 형식 8비트

컴퓨터는 7비트값을 처리하도록 설계되지 않아 8비트를 사용해 아스키 문자를 저장합니다. 8비트만 사용하면 모든 문자를 표현할 수 있는데 16비트를 사용해 낭비하기 싫어서 한 문자를 8비트로 표현합니다. 유니코드는 문자 코드에 각기 다른 인코딩을 사용하여 이 문제를 해결합니다. 인코딩은 다른 비트 패턴을 표현하기 위해 사용하는 비트 패턴을 말합니다. 유니코드 변환 형식 8비트(UTF-8)는 모든 아스키 문자를 8비트로 표현하기 때문에 아스키 데이터를 인고딩할 때는 추가 공간이 필요하지 않습니다.
UTF-8은 문자를 8비트 덩어리의 시퀀스로 인코딩합니다.

문자를 사용한 수 표현

출력 가능하게 변경한 인코딩

출력 가능하게 변경한 인코딩(Quoted-Printable encoding)은 쿼티드 프린터블 인코딩, 혹은 QP 인코딩이라고도 합니다. 이는 8비트 데이터를 7비트 데이터만 지원하는 통신 경로를 통해 송수신하기 위한 인코딩 방법입니다. 해당 인코딩은 전자우편 첨부를 처리하기 위해 만들어졌습니다. 해당 인코딩을 사용하면 = 다음에 추가로 16진 숫자 2개를 추가해 8비트 값을 표현합니다. =가 특별한 의미를 지니기 때문에 QP에서 =를 표현하려면 =3D를 사용해야 합니다.
추가로 줄의 맨 끝에 탭과 공백 문자가 온다면 이를 각각 =09, =20으로 표현해야 합니다. 인코딩된 데이터는 한 줄이 76자를 넘을 수 없어서 어떤 줄의 맨 뒤가 =로 끝나면 가짜 줄바꿈을 뜻하며 수신 쪽에서 QP로 인코딩된 데이터를 디코딩할 때는 이 =를 제거하고 해석합니다.

베이스64 인코딩

QP인코딩은 1바이트를 표현하기 위해 3바이트를 사용하기 때문에 비효율적입니다. 따라서 base64인코딩을 주로 사용합니다. 이는 3바이트 데이터를 4문자로 표현합니다. 3바이트 데이터의 24비트를 네 가지 6비트 덩어리로 나누고 각 덩어리의 6비트값에 출력 가능한 문자를 할당해 표현합니다.
표 1-13

그림 1-17
이 인코딩은 모든 3바이트 조합을 4바이트 조합으로 변환할 수 있습니다. 만약 원본 데이터가 2바이트 남으면 끝에 =를 붙이고 1바이트가 남으면 끝에 ==를 붙입니다. base64 인코딩 방식은 전자우편 첨부파일 전송에 많이 사용중입니다.

URL 인코딩

URL이라는 문맥에서 몇몇 문자는 특별한 의미를 지닙니다. 이런 특별한 의미를 지니는 문자를 문자 그대로 사용할 필요가 있씁니다. 문자들은 8비트 덩어리의 시퀀스로 표현됩니다. URL 인코딩은 퍼센트 인코딩이라고도 부르는데, % 뒤에 어떤 문자의 16진 표현을 덧붙이는 방식으로 문자를 인코딩합니다. 예를 들어, /는 URL에서 특별한 의미를 지니는데 이 문자를 16진수로 표현하면 2F입니다. /를 URL에 사용하되 /가 표현하는 특별한 의미를 뜻하고 싶지 않은 경우, /를 %2F 라는 문자열로 대신하면 됩니다.

profile
블로그 이전했습니당 https://halang.tech

0개의 댓글