---
description: 컴퓨터는 어떤 말을 사용할까?
---

# 1장 : 컴퓨터 내부의 언어 체계

{% hint style="success" %}
1장에서는 컴퓨터의 언어를 배우기 시작한다.
{% endhint %}

언어는 정보를 서로 소통하기 위해 만들어졌는데 프로그래머가 해야 할 일은 컴퓨터에게 명령을 내리는 것이다.&#x20;

> 그런데 컴퓨터는 사람의 말을 알아듣지 못한다.

따라서 사람이 컴퓨터의 말을 배워야 한다. 자연어와 컴퓨터 언어는 쓰인 기호나 제대로 된 기호 나열 방법, 사용법 등의 요소를 상당 부분 공유한다. 자연어가비문자 언어라는 것과 달리 **컴퓨터 언어**는 항상 <mark style="color:red;">문자 언어만 사용</mark>한다.

## 1. 언어란 무엇인가

{% hint style="success" %}
언어는 **편의를 제공하기 위한 지름길**이다.
{% endhint %}

모든 언어의 뜻은 **기호의 집합으로 인코딩**된다. 하지만 의미를 기호로 인코딩하는 것만으로는 충분하지 않다.

> 언어가 제대로 작동하려면 의사소통하는 당사자들이 모두 같은 **문맥**을 공유해서 같은 기호에 같은 뜻을 <mark style="color:red;">부여할 수 있어야 한다.</mark>

<figure><img src="https://498337729-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqKPDlntOwGZBfzPFGkYi%2Fuploads%2Fm8tJPiPFXb3PIM5kCAbs%2Fimage.png?alt=media&#x26;token=70043218-4d6e-4994-98ef-db09416e79d5" alt=""><figcaption></figcaption></figure>

동일한 기호를 구분할 수 있는 요소는 문맥뿐인데, **언제나 문맥을 명확히 식별할 수 있는 것은 아니다.** 컴퓨터 언어에도 마찬가지 문제가 있다.

## 2. 문자 언어

{% hint style="success" %}
**문자 언어**는 기호를 나열한 것이다. 기호를 정해진 순서대로 단어를만들 수 있다.
{% endhint %}

**기호나 조합**은 무궁무진한 가능성이 있다. 언어마다 기호와 기호 유형이 달라질 수 있고, 언어마다 **순서**도 다를 수 있다.

기호의 순서도 중요하다. ‘dog’와 ‘god’는 같지 않다.

### 컴퓨터 언어에서도 3가지 구성 요소

* 기호가 들어갈 상자
* 상자에 들어갈 기호
* 상자의 순서

> 일부 언어에는 주변의 상자 안에 들어 있는 기호의 종류에 따라 상자에 들어갈 수 있는 기호를 제한하는 **복잡한 규칙**이 존재하기도 한다.

예를 들어, 어떤 기호들은 서로 인접한 상자에 들어 갈 수 없다.

## 3. 비트

먼저 **상자**에 대해 생각해보자.

{% hint style="warning" %}
자연어에서는 이 상자를 **문자**라고 부르고, 컴퓨터에서는 **비트**라고 부른다.
{% endhint %}



* 비트 = 바이너리(binary) + 디지트(digit)
  * 바이너리 : 2진법 사용한다는 뜻으로, **두 가지 부분으로 이뤄진 어떤 대상**을 뜻한다.
  *   디지트 : 숫자를 뜻하며,  일상생활에서 쓰는 10진수를 표현 하는 10가지 기호(0\~9)를 뜻한다.

      <figure><img src="https://498337729-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqKPDlntOwGZBfzPFGkYi%2Fuploads%2F5gTPSnxiQSV2OOY9Ccms%2Fimage.png?alt=media&#x26;token=dc08ce85-1709-4000-a53d-565ae11b2484" alt=""><figcaption></figcaption></figure>

> 기묘한 바이너리와 디지트의 결합인 비트로, 비트는 적은 비용으로 편리하게 기호를 담을 수 있음

비트는 **2진법**을 사용한다.&#x20;

* 비트 상자에는 모스 부호의 점(.)과 선(-)처럼 두 가지 기호 중 하나만 담을 수 있다는 뜻
* **모스 부호**는 두 기호를 여러 가지 방식으로 조합해 이어붙여서 복잡한 정보를 표현한다.
  * 예를 들어 A는 점-선이고, B는 선-점-점-점, C는 선-점-선-점이다. 자연어와 마찬가지로 기호의 순서가 중요하다.
  * 선-점은 A가 아니라 N이다.

### 기호

기호라는 개념은 추상적이다. 실제로는 기호가 무엇이든 관계없다.

{% hint style="danger" %}
하지만 가장 중요한 것은 **언어는 문맥 없이는 제대로 작동할 수 없다.**
{% endhint %}

#### 1. **기호의 추상성**

* 기호 자체는 무엇이든 될 수 있으며, 특정한 형태를 가질 필요가 없다.
* 예를 들어, **꺼짐/켜짐, 낮/밤, 쌀/보리** 등 다양한 방식으로 표현될 수 있다.

#### 2. **언어와 문맥의 중요성**

* 언어는 문맥이 있어야 제대로 작동한다.
* 같은 기호라도 **말하는 사람과 듣는 사람이 다르게 해석하면 혼란이 발생할 수 있음**.
* 예: "U(점-점-선)"을 말하는 사람이 의도했지만, 상대가 "쌀-쌀-보리"로 해석하면 의미가 어긋남.

#### 3. **컴퓨팅에서 비트의 의미 부여**

* 컴퓨터에서 계산을 수행하는 방식을 **컴퓨팅**이라 부름.
* 비트 자체는 의미가 없으며, **필요에 따라 의미를 부여하는 방식(척하기)이 중요**.
* 예를 들어, "이 비트들은 파란색을 뜻한다고 가정하자"처럼 의미를 임의로 정할 수 있음.

#### 4. **프로그래밍과 비트의 활용**

* 표준적인 비트 사용법을 배우는 것도 중요하지만,\
  **필요에 따라 자신만의 방식으로 비트를 활용하는 것을 두려워할 필요 없음**.
* 프로그래밍은 본질적으로 <mark style="color:red;">비트에 특정 의미를 부여하는 과정</mark>이다.

> 컴퓨터에서 사용되는 기호와 비트는 본질적으로 **문맥에 따라 의미가 달라지며, 필요에 따라 유연하게 해석될 수 있다**. 프로그래밍은 이런 유연성을 바탕으로 다양한 표현을 가능하게 한다.

## 4. 논리 연산

**비트 사용법** 중 하나는 “날씨가 추운가?”, “내 모자를 좋아하나?”와 같은 예/아니요 질문에 대 한 답을 표현하는 것이다.&#x20;

> 이때 ‘예’를 참true이라는 용어로 부르고, ‘아니요’를 거짓false이라고 부른다.

<figure><img src="https://498337729-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqKPDlntOwGZBfzPFGkYi%2Fuploads%2FVuphuzorTz397eCI9UPW%2Fimage.png?alt=media&#x26;token=46d75c01-98ad-482b-8ec7-b777779f06ed" alt=""><figcaption></figcaption></figure>

{% hint style="success" %}
다른 비트들이 표현하는 내용으로부터 **새로운 비트를 만들어내는 이런 동작**을 논리 연산logic operation이라고 한다.
{% endhint %}



### 1) 불리언 대수

{% hint style="info" %}
불리언 대수Boolean algebra도 비**트에 대해 사용할 수 있는 연산 규칙의 집합**
{% endhint %}

일반 대수와 마찬가지로 결합 법칙, 교환 법칙, 분배 법칙을 불리언 대수에 적용할 수 있다.



<figure><img src="https://498337729-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqKPDlntOwGZBfzPFGkYi%2Fuploads%2FoMsyqaHOJMbcCxsx0TYs%2Fimage.png?alt=media&#x26;token=c9fd333a-f2de-4836-9cb2-436916dc2803" alt=""><figcaption><p>불리언 연산을 진리표truth table라는 틀을 사용해 시각적으로 요약해 보여준다.</p></figcaption></figure>

`입력 input`은 박스의 밖에 있고, `출력output`은 박스 안에 있다.

<figure><img src="https://498337729-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqKPDlntOwGZBfzPFGkYi%2Fuploads%2FPEIvBa8ghTKd6aOt4pIN%2Fimage.png?alt=media&#x26;token=c7d9d8a9-3e56-4d99-ac2e-593a392be91f" alt=""><figcaption></figcaption></figure>

* **NOT:**  **‘논리적 반대’를 의미**한다. 예를 들어, 거짓인 비트에 NOT을 하면 참이 되고 참인 비트에 NOT을 하면 거짓이 된다.&#x20;
* **AND: 둘 이상의 비트에 작용**한다. 2비트 연산인 경우 첫 번째 비트가 참이고 두 번째 비트도 참인 경우에만 결과가 참이 된다. 2비트보다 더 많은 비트에 연산을 적용하는 경우 <mark style="color:red;">모든 비트가 참이면 AND 연산의 결과도 참이다.</mark>&#x20;
* **OR:** **둘 이상의 비트에 작용**한다. 2비트 연산인 경우 첫 번째 비트가 참이거나 두 번째 비트가 참이면 결과가 참이 된다. 2비트보다 더 많은 비트에 연산을 적용하는 경우 <mark style="color:red;">어느 한 비트라도 참이면 OR 연산의 결과도 참이다.</mark>&#x20;
* **XOR:** 이 배타적(exclusive OR)의 결과는 <mark style="color:red;">첫 번째 비트와 두 번째 비트가 다른 값인 경우에만 참이 된다</mark>. &#xC989;**, 두 값 중 어느 하나가 참이면 XOR도 참이지만 두 값이 모두 참이면 XOR의 결과는 거짓이다**.

> 다른 연산을 사용해 XOR 연산을 만들 수 있다. 예를 들어, 두 비트에 대한 **XOR 연산(a XOR b)은 (a OR b) AND (NOT(a AND b))**&#xC640; 같다. 이를 통해 기본 불리언 연산을 <mark style="color:blue;">다양한 방식으로 조합해 똑같은 결과를 얻을 수 있다는 사실</mark>을 알 수 있다.

### 2) 드모르간의 법칙

오거스터스 드모르간은 불리언 대수에 적용할 수 있는 법칙을 추가로 알아냈다. 발명자의 이름을 따서 `드모르간의 법칙`이라고 한다.

{% hint style="warning" %}
**a AND b  = NOT(NOT a OR NOT b)**
{% endhint %}

<figure><img src="https://498337729-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqKPDlntOwGZBfzPFGkYi%2Fuploads%2Frmmfc68A4YSrsloZY07o%2Fimage.png?alt=media&#x26;token=35c8b00c-a070-450a-a9aa-ef6824effa83" alt=""><figcaption></figcaption></figure>

`NOT`을 충분히 사용하면 `AND 연산을 OR 연산`**으로 대신**할 수 있다(그리고 역으로 OR을 AND로 대신할 수 있다)는 뜻이다.

컴퓨터에서 입력을 항상 원하는 형태로 얻을 수만은 없기 때문에 이런 성질이 유용할 때가 있다. 자연어에서 이중 부정이 이와 비슷한 일을 한다.

> 지금까지 살펴본 **긍정적인 논리positive logic에 더해 부정적인 논리negative logic를 기술하는 명제를 사용할 때** `드모르간의 법칙`을 활용할 수 있다.

{% hint style="success" %}
부정논리도 작동하나. **연산을 최소로 사용하면 비용을 최소화**할 수 있다. 여기서는 **NOT 연산을 수행**하는 <mark style="color:red;">하드웨어에 실제로 돈이 들기도 하고</mark>, 다음 장에서 보겠지만 <mark style="color:red;">연산을 연쇄적으로 사용하면 계산이 느려진다.</mark>
{% endhint %}

<figure><img src="https://498337729-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqKPDlntOwGZBfzPFGkYi%2Fuploads%2FwXgzmFHid8i0NDMDG4Ct%2Fimage.png?alt=media&#x26;token=f77f5b7d-1f63-485c-915a-4304aa212248" alt=""><figcaption></figcaption></figure>

드모르간의 법칙을 알면 두 번째 표가 표현하는 논리가 **‘춥다 OR 비가 온다’와 동등함**을 알 수 있고, **훨씬 간단하게 결과를 계산할 수 있다.**

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

> 비트를 사용해 **수를 표현하는 방법**을 알아보자. 수는 논리보다 더 복잡하지만 단어보다는 훨씬 단순하다.

### 1) 양의 정수 표현

#### **1. 10진수 체계**

* 우리는 손가락과 발가락이 10개이기 때문에 10진수를 사용함.
* 10가지 숫자(0\~9)를 사용하며, 숫자는 오른쪽에서 왼쪽으로 **자리값**이 증가함.
* 각 자리값은 **10의 거듭제곱(1, 10, 100, 1000 등)**&#xC73C;로 표현됨.
* 예: 5,028 = **5×10³ + 0×10² + 2×10¹ + 8×10⁰**

<figure><img src="https://498337729-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqKPDlntOwGZBfzPFGkYi%2Fuploads%2FBeOPZ64yMggKDxBUmpGr%2Fimage.png?alt=media&#x26;token=439bd590-aa9a-4083-b14e-33ea5031fa40" alt=""><figcaption><p>거듭제곱 자리 수 하나당 1개의 상자라고 볼 수 있음<strong>(10진수 하나 당 상자 하나)</strong></p></figcaption></figure>

#### **2. 2진수 체계**

{% hint style="warning" %}
각 상자에 사용할 수 있는 기호는 1과 0 두 가지밖에 없다. 하지만 기호가 2개뿐이라고 문제가 되지는 않는다. 10진수에서 수를 표현할 수 없을 때는 **더 큰 수를 표현하기 위해 상자 를 추가할 수 있었다**
{% endhint %}

* 2진수는 0과 1만 사용하며, 자리값은 2의 거듭제곱(1, 2, 4, 8, 16, ...)을 기반으로 함.
* 10진수에서 자릿수를 늘려서 더 큰 수를 표현하는 것처럼, 2진수에서도 비트(자리)를 추가하면 더 큰 수를 표현할 수 있음.
* 1보다 큰 수를 표현하려면 새로 상자를 추가해야 함
* 예: 5,028을 2진수로 변환
  * 5,028 = **1×2¹² + 0×2¹¹ + 0×2¹⁰ + 1×2⁹ + 1×2⁸ + 1×2⁷ + 0×2⁶ + 1×2⁵ + 0×2⁴ + 0×2³ + 1×2² + 0×2¹ + 0×2⁰**
  * 결과: **1001110100100₂**

<figure><img src="https://498337729-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqKPDlntOwGZBfzPFGkYi%2Fuploads%2F718pXkAReKn2FymGLxHs%2Fimage.png?alt=media&#x26;token=8a2e7310-65b6-4277-b270-8989fa340d09" alt=""><figcaption></figcaption></figure>

#### **3. 비트 개수와 표현 범위**

* 비트 개수가 많을수록 표현할 수 있는 값의 범위가 커짐. 표현할 수 있는 수의 범위가 커진다.

<figure><img src="https://498337729-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqKPDlntOwGZBfzPFGkYi%2Fuploads%2FJ2g7TofUs7MEYJLBUyc9%2Fimage.png?alt=media&#x26;token=04cb673c-7975-4599-9461-63c8305d74f5" alt=""><figcaption></figcaption></figure>

* 예:
  * 4비트 → 0\~15 (16개)
  * 8비트 → 0\~255 (256개)
  * 16비트 → 0\~65,535 (65,536개)
  * 32비트 → 0\~4,294,967,295 (약 43억 개)
  * 64비트 → 0\~18,446,744,073,709,551,615 (약 18경 개)

#### **4. 가장 큰 유효 비트(MSB)와 가장 작은 유효 비트(LSB)**

<figure><img src="https://498337729-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqKPDlntOwGZBfzPFGkYi%2Fuploads%2FO8GvvTW7FPconHmpAOnY%2Fimage.png?alt=media&#x26;token=62a923ee-b397-495a-8596-fe82542faf33" alt=""><figcaption></figcaption></figure>

* **LSB (Least Significant Bit)**: 2진수에서 가장 오른쪽 비트 (값 변화가 가장 작음).
* **MSB (Most Significant Bit)**: 2진수에서 가장 왼쪽 비트 (값 변화가 가장 큼).
* 예: **5,028(1001110100100₂)에서 MSB는 맨 왼쪽 1, LSB는 맨 오른쪽 0**

#### **5. 리딩 제로 (Leading Zero)**

* 2진수에서 더 많은 비트를 사용할 경우, 앞쪽에 0을 추가해도 값은 변하지 않음.
  * 10진수와 마찬가지로 가장 왼쪽에 있는 상자보다 더 왼쪽에 영(0)을 추가하면(이 런 식으로 추가된 영들을 리딩 제로leading zero라고 말한다)&#x20;
  * 어떤 값을 표현하는 데 필요한 **최소한의 상자 개수보다 더 많은 상자를 추가할 수 있다.**
* 예: **5,028을 16비트로 표현하면 0001001110100100**
* 10진수에서도 **5,028과 05,028은 같은 값**

{% hint style="success" %}
컴퓨터가 **미리 정해진 수의 비트를 한 덩어리로 사용하도록 만들어졌기 때문에**, 2진수를 쓸 때는 이런 식으로 항상 일정한 개수의 비트를 사용해 값을 표현하는 경우가 종종 있다.
{% endhint %}

### 2) 2진수 덧셈

{% hint style="warning" %}
10진 덧셈에서 오른쪽에서 왼쪽으로 각 자리의 숫자를 서로 더한 것처럼 마찬가지로, 2진수에서도 각 비트를 LSB에서 MSB 쪽으로 더하며 **결과가 1보다 크면 1을 다음 자리(왼쪽)로 올린다.**
{% endhint %}

이 글은 **2진수 덧셈의 원리, 논리 연산을 활용한 계산 방식, 오버플로와 언더플로 개념**을 설명한다.

#### **1. 2진수 덧셈 원리**

* **10진수 덧셈**: 오른쪽(Lowest Significant Bit, LSB)부터 더하며, 9를 초과하면 1을 올림.
* **2진수 덧셈**: 1+1은 2이지만, 2진수에서는 2가 없으므로 10(1 올림, 0 유지)로 변환.

예) **1(001₂) + 5(101₂) = 6(110₂)**

1. LSB(맨 오른쪽): 1+1 = **10** → 0을 남기고 1을 올림.
2. 중간 자리: 0+0에 올림(1) 추가 → 1.
3. MSB(맨 왼쪽): 0+1 = 1.
4. 최종 결과: **110₂ (10진수 6과 동일함).**

#### **2. 논리 연산을 활용한 2진수 덧셈**

<figure><img src="https://498337729-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqKPDlntOwGZBfzPFGkYi%2Fuploads%2FhT6ELswUGpzQPxATMtcD%2Fimage.png?alt=media&#x26;token=2bc5239f-1a0f-4fc0-97e0-6404eebae8ea" alt=""><figcaption></figcaption></figure>

* **XOR(배타적 논리합, Exclusive OR):** 각 비트를 더한 <mark style="color:red;">결과를 결정.</mark>
  * 0+0 = 0, 1+0 = 1, 0+1 = 1, 1+1 = 0 (<mark style="color:red;">올림</mark> 발생).
* **AND(논리곱, AND):** <mark style="color:red;">올림을 결정.</mark>
  * 0 AND 0 = 0, 1 AND 0 = 0, 0 AND 1 = 0, 1 AND 1 = 1 (<mark style="color:red;">올림</mark> 발생).

예)

* 1 + 1 → **AND(1), XOR(0)  → 올림**
* 1 + 0 → **AND(0), XOR(1)  → 올림 없음**

3비트 이상 덧셈에서는 2비트 덧셈을 두 번 수행하면 됨.

#### **3. 오버플로(Overflow)와 언더플로(Underflow)**

* **오버플로**: 덧셈 결과가 사용 가능한 <mark style="color:red;">비트 범위를 초과</mark>하는 경우.
  * 예) 4비트로 9(1001₂) + 8(1000₂) = 17(10001₂) → MSB를 초과한 1이 손실됨(결과: 0001₂, 즉 1).
  * 컴퓨터는 **오버플로 비트**를 사용하여 이런 문제를 감지.
* **언더플로**: 뺄셈 시 <mark style="color:red;">MSB 위쪽에서 1을 빌려와야 하는 경우.</mark>
  * 컴퓨터에는 **조건 코드(상태 코드) 레지스터**가 있어 몇 가지 이상한 정보를 담아둔다.
    * 이런 정보 중에는 오버플로 비트overflow bit가 있고, 이 비트에는 MSB에서 발생 한 올림값이 들어간다.
    * 이 비트값을 보면 오버플로가 발생했는지 알 수 있다
    * 이에 해당하는 조건 코드도 컴퓨터에 들어 있다.

#### **4. 뺄셈과 음수 표현(다음 절 예고)**

* 뺄셈은 사실상 **덧셈으로 변환 가능** (예: 7 - 5 = 7 + (-5)).
* 음수를 표현하는 방법(2의 보수 등)을 설명할 예정.

#### **결론**

* 2진수 덧셈은 **XOR로 결과, AND로 올림**을 계산하면 된다.
* 오버플로와 언더플로는 **비트 범위를 벗어날 때 발생**하며, 컴퓨터는 이를 감지하는 조건 코드를 사용한다.
* 음수 표현과 뺄셈은 덧셈으로 변환 가능하다.

**오버플로우와 언더플로우 방지 방법**&#x20;

* **입력 유효성 검사:** 사용자 입력을 받을 때 입력 값의 범위를 검사하여 유효한 값만 처리하도록 한다.
* **데이터 타입 변경:** 더 큰 정수 데이터 타입을 사용하거나, 부호 없는 데이터 타입을 사용하여 정수 오버플로우를 줄일 수 있다

### 3) 음수표현

{% hint style="info" %}
실제 세계에서 문제를 해결하려면 양수와 음 수를 모두 사용해야 하는 경우가 많다
{% endhint %}

**1. 음수를 표현하는 필요성**

앞 절까지는 양수만 다루었지만, 실제로는 <mark style="color:red;">양수와 음수를 모두 표현해야 하는 경우가 많다.</mark>\
4비트로 표현할 수 있는 값이 16가지(0\~15)이지만, 이를 음수를 포함하는 표현법으로 바꿀 수 있음.\
비트의 해석 방식(문맥)을 다르게 하면 같은 비트 패턴도 다른 의미를 가질 수 있음.

{% hint style="danger" %}
기억하자. 언어는 문맥과 의미를 통해 작용하기 때문에 **이 말은 비트들을 해석하는 새로운 문맥을 만들 수 있다는 뜻이다.**
{% endhint %}

#### **2. 부호와 크기(Sign and Magnitude) 표현법**

{% hint style="warning" %}
음수와 양수를 비교하기 위해 부호를 쓰는데 부호는 +, -로 2가지 값이 있으므로 **이를 비트 하나로 표현할 수 있다.**
{% endhint %}

* **가장 왼쪽 비트(MSB, Most Significant Bit)를 부호 비트**로 사용하고, <mark style="color:red;">나머지 비트는 숫자의 크기(절댓값)</mark>를 나타냄.
* 따라서 4비트 중에 3비트가 남고, 이를 사용하면 0부터 7까지 수를 표현할 수 있다.
* MSB = 0 → 양수, MSB = 1 → 음수. (부호비트)
* 즉, 0부터의 거리(절댓값)을 표현하기 위해 사용하는 이런 방법을 부호와 크기 표현법이라고 말한다.

예:

* `0111₂` → `+7`
* `1111₂` → `-7`
* `0000₂` → `+0`
* `1000₂` → `-0` (**0이 두 개 존재하는 문제 발생!**)

**문제점**

**① 0이 두 가지로 표현됨**

* `0000₂` = `+0`, `1000₂` = `-0`
* 같은 숫자를 표현하는 방법이 두 개 존재하여 비효율적임.
* 비트를 구성하려면 돈이 듦, 낭비

**② 연산이 제대로 동작하지 않음**

* 예를 들어, `+1(0001₂) + (-1)(1001₂)`을 연산하면
  * **XOR과 AND 연산을 수행하면 결과가 `1010₂(-2)`가 됨**.
  * **+1과 -1을 더하면 0이 나와야 하는데, -2가 나옴** → 연산 오류 발생.

**③ 추가적인 연산 로직이 필요**

* 덧셈, 뺄셈을 정상적으로 수행하려면 별도의 복잡한 논리 연산을 추가해야 함.
* 이러한 복잡성을 줄이기 위해 더 나은 방법이 필요함.

부호와 크기 표현법은 0이 중복되고 연산이 자연스럽게 수행되지 않기 때문에 **현대 컴퓨터에서는 사용되지 않는다.**

#### **3. 1의 보수(One’s Complement) 표현법**

{% hint style="danger" %}
**양수의 모든 비트를 뒤집으면(반전, NOT 연산) 음수**가 된다.
{% endhint %}

예:

* `+7(0111₂) → -7(1000₂)`
* `+3(0011₂) → -3(1100₂)`

**문제점**

1. 0이 두 가지(+0, -0)로 표현됨 → `0000₂ (+0)`과 `1111₂ (-0)`, 부호와 크기 표현법과 같은 문제.
2. 덧셈 시 **순환 올림(End-Around Carry)** 처리가 필요 → 복잡한 하드웨어 요구. →  비용이 더 든다.

> **순한올림**이란 MSB 쪽에서 올림이 발생한 경우에 는 LSB로 올림을 전달해야 하는 것

<figure><img src="https://498337729-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqKPDlntOwGZBfzPFGkYi%2Fuploads%2FCHr321E6ldw1ayTafjWG%2Fimage.png?alt=media&#x26;token=b9c07fd3-62f2-45c9-8f86-b02c81771a9a" alt=""><figcaption></figcaption></figure>

1의 보수도 0이 중복되고 연산 처리가 복잡하여 현대 시스템에서 사용되지 않음.

#### **4. 2의 보수(Two’s Complement) 표현법 (현대 컴퓨터 표준)**

{% hint style="success" %}
1의 보수에 1을 더하면 2의 보수가 됨.   가장 널리 사용되는 음수 표현 방식이다.
{% endhint %}

> 특별한 하드웨어를 추가할 수 없고 **XOR과 AND 연산만 사용해야 한다면** 어떻게 일반 정수 사이의 덧셈을 할 수 있을까?&#x20;

* +1에 더했을 때 0이 나오는 비트 패턴을 찾고 이 패턴을 -1이라고 불러보자.
  * 4비트 수의 경우 +1은 0001이다.
  * 1111을 0001에 더하면 0000이 된다.
  * 앞으로는 1111을 (4비트에서) -1을 표현하는 비트 패턴으로 사용하자.

<figure><img src="https://498337729-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqKPDlntOwGZBfzPFGkYi%2Fuploads%2F226vGsLBWHRDXtquQaJb%2Fimage.png?alt=media&#x26;token=81411bb1-dd37-4333-a72b-69d04ec9fff0" alt=""><figcaption></figcaption></figure>

**2의 보수 변환 방법**

> 부호가 있는 정수를 표현할 때 가장 널리 쓰이는 방법이다.

1. 비트를 반전(즉 각 비트의 NOT을 취하고)
2. 1을 더함  → 이때 MSB에서 <mark style="color:red;">올림이 발생하면 이 값은 버린다.</mark>

**예제: 4비트 2의 보수 표현**

| **2의 보수(4비트)** | **10진수 값** |
| :------------: | :--------: |
|     `0111₂`    |    `+7`    |
|     `0110₂`    |    `+6`    |
|     `0101₂`    |    `+5`    |
|     `0100₂`    |    `+4`    |
|     `0011₂`    |    `+3`    |
|     `0010₂`    |    `+2`    |
|     `0001₂`    |    `+1`    |
|     `0000₂`    |    `+0`    |
|     `1111₂`    |    `-1`    |
|     `1110₂`    |    `-2`    |
|     `1101₂`    |    `-3`    |
|     `1100₂`    |    `-4`    |
|     `1011₂`    |    `-5`    |
|     `1010₂`    |    `-6`    |
|     `1001₂`    |    `-7`    |
|     `1000₂`    |    `-8`    |

* `+1(0001₂) → -1(1111₂)` (비트 반전 `1110₂` + `1`)
* `+2(0010₂) → -2(1110₂)` (비트 반전 `1101₂` + `1`)
* `+7(0111₂) → -7(1001₂)`

#### **5. 2의 보수의 장점 (현대 컴퓨터에서 사용하는 이유)**

* 0이 중복되지 않음 → `0000₂ (+0)`만 존재함.

{% hint style="danger" %}
왜 2의 보수에서는 0이 하나만 존재하는가?
{% endhint %}

부호와 크기 표현법(Sign and Magnitude)과 1의 보수(One’s Complement) 방식에서는 **+0과 -0이 중복해서 존재하는 문제가 있었다.**

하지만 **2의 보수에서는 0이 하나만 존재**한다.

**확인 과정:**

1. `0000₂`(0)의 모든 비트를 반전하면 → `1111₂`(1의 보수)
2. 여기에 1을 더하면 → `0000₂` (**초기 값과 동일**)
3. 따라서 **0이 하나만 존재하게 됨**.

* 덧셈 연산이 자연스럽게 동작 → `+1(0001₂) + (-1)(1111₂) = 0000₂ (0)`
* 하드웨어 구현이 간단 → 별도의 연산 처리 없이 정수 덧셈과 동일한 방식으로 수행 가능.

#### **6. 2의 보수로 표현할 수 있는 값의 범위**

N비트의 2의 보수 표현법에서는 다음과 같은 범위를 표현할 수 있다.

{% hint style="danger" %}
int, Long 등 **데이터 타입의 비트 수에 따라 표현할 수 있는 값의 범위가 달라짐** 그렇기 때문에 프로그래머들은 거의 본능처럼 이런 계산을 수행한다.
{% endhint %}

| **비트 개수** | **값의 개수**                   | **표현 가능한 값의 범위**                                            |
| --------- | --------------------------- | ----------------------------------------------------------- |
| 4비트       | 16개                         | **-8 \~ 7**                                                 |
| 8비트       | 256개                        | **-128 \~ 127**                                             |
| 16비트      | 65,536개                     | **-32,768 \~ 32,767**                                       |
| 32비트      | 4,294,967,296개              | **-2,147,483,648 \~ 2,147,483,647**                         |
| 64비트      | 18,446,744,073,709,551,616개 | **-9,223,372,036,854,775,808 \~ 9,223,372,036,854,775,807** |

2의 보수 표현법에서는 가장 큰 양수는 011...111 (N-1개의 1)이고, 가장 작은 음수는 100...000 (N비트에서 MSB만 1, 나머지는 0).

> 비트 개수가 커지면 표현할 수 있는 값의 범위가 **지수적으로 증가**한다.\
>
>
> 2의 보수에서는 **N비트일 때 표현할 수 있는 정수의 범위는**
>
> −(2N−1)   (2N−1−1)- (2^{N-1}) \text{ \~ } (2^{N-1} - 1)

**7. 음수 변환(2의 보수) 손으로 계산하는 방법**

예제: `-13`을 8비트 2의 보수로 변환

1. `13`을 2진수로 변환 → `0000 1101₂`
2. 비트 반전(NOT 연산) → `1111 0010₂`
3. 1을 더함 → `1111 0011₂` (2의 보수)

`-13`의 2의 보수 표현 = `1111 0011₂`

#### **8. 같은 비트 패턴이라도 표현법에 따라 값이 달라짐**

같은 4비트 숫자라도 **표현법에 따라 해석이 달라질 수 있다.** 문맥에 따라 표현하는 값이 달라질 수 있다는 점을 꼭 염두에 둬야 한다.

예제: `1111₂`

* **부호와 크기(Sign and Magnitude)** → `-7`
* **1의 보수(One’s Complement)** → `-0`
* **2의 보수(Two’s Complement)** → `-1`

{% hint style="success" %}
즉, 같은 2진수라도 어떤 표현법을 사용하느냐에 따라 해석이 달라지므로, <mark style="color:red;">사용 중인 표현법을 정확히 알아야 한다.</mark>
{% endhint %}

#### **9. 2의 보수로 변환하는 방법 (손으로 직접 계산하는 법)**

2의 보수로 변환하는 방법을 익히면 **손으로 직접 음수를 표현할 수 있다.**

**양수를 2의 보수로 변환 (예: -6)**

1. **6을 2진수로 변환** → `0110₂`
2. **비트를 반전 (NOT 연산)** → `1001₂`
3. **1을 더함** → `1010₂` (즉, -6의 2의 보수 표현)

{% hint style="success" %}
따라서 **`-6`의 4비트 2의 보수 표현은 `1010₂`가 된다.**
{% endhint %}

**2의 보수를 이용한 뺄셈 (예: 5 - 3)**

1. 5의 2진수 표현: `0101₂`
2. 3의 2진수 표현: `0011₂`
3. `-3`을 구하려면 **비트 반전 후 1을 더함**
   * `0011₂` → `1100₂` (반전)
   * `1101₂` (1을 더함 → `-3`)
4. 이제 `5 + (-3)`을 계산
   * `0101₂` + `1101₂`
   * 결과: `10010₂` → 5비트지만, 4비트만 보면 `0010₂`
   * **즉, 2(10진수)로 정상적으로 계산됨!**



#### **\[추가 설명 및 배경 지식]**

**1. 현대 컴퓨터가 2의 보수를 사용하는 이유**

* 덧셈 연산을 동일한 방식으로 처리 가능 → **별도의 하드웨어 필요 없음.**
* 0이 하나만 존재 → 저장 공간 낭비 없음.
* CPU에서 음수 연산이 효율적으로 가능 → 1의 보수, 부호와 크기 방식보다 처리 속도가 빠름.

**2. 프로그래밍 언어에서의 2의 보수**

대부분의 프로그래밍 언어(C, Java, Python)는 2의 보수를 사용해 음수를 표현.

예제:

```c
int a = -5;
printf("%d", a);
```

메모리에서 `-5`는 2의 보수 형태(예: 1111 1011₂)로 저장됨.



#### **\[결론]**

* **2의 보수 표현법은 현대 컴퓨터에서 가장 널리 사용되는 음수 표현 방식이다.**
* **0이 하나만 존재**하기 때문에 불필요한 중복이 없음.
* **비트 수에 따라 표현할 수 있는 정수의 범위가 달라지며, 비트 수가 증가할수록 범위가 지수적으로 증가함.**
* **같은 2진수라도 어떤 표현법을 사용하는지에 따라 해석이 달라질 수 있으므로 항상 사용 중인 표현법을 알아야 함.**
* **2의 보수를 사용하면 덧셈과 뺄셈이 자연스럽게 이루어지며, 연산이 효율적이고 하드웨어 구현이 용이함.**

### 4) 추가 : 덧셈 연산에서 XOR이 중요한 이유와 별도 하드웨어 필요성

{% hint style="success" %}
컴퓨터에서 덧셈을 수행할 때 **XOR(배타적 논리합, Exclusive OR)과 AND(논리곱) 연산을 활용하는 이유는 하드웨어 구현이 간단하고 효율적이기 때문**이다.&#x20;
{% endhint %}

만약 XOR 대신 다른 논리 연산을 사용하려 하면, **별도의 추가 연산 장치가 필요**할 수도 있다.

#### **1. XOR을 이용한 2진수 덧셈 원리**

2진수 덧셈을 살펴보면, 각 비트의 덧셈 결과는 다음과 같다.

|  A  |  B  | 합(Sum) | 올림(Carry) |
| :-: | :-: | :----: | :-------: |
|  0  |  0  |    0   |     0     |
|  0  |  1  |    1   |     0     |
|  1  |  0  |    1   |     0     |
|  1  |  1  |    0   |     1     |

여기서

* **합(Sum)** = `A XOR B`
* **올림(Carry)** = `A AND B`

이렇게 하면 덧셈을 수행하는 회로(반가산기, Half Adder)를 XOR과 AND만으로 만들 수 있다.

#### **2. XOR을 사용하지 않는다면?**

덧셈 결과를 결정하는 기본적인 규칙을 따르려면 다음과 같은 계산이 필요하다.

1. `0 + 0 = 0`
2. `0 + 1 = 1`
3. `1 + 0 = 1`
4. `1 + 1 = 0` (올림 발생)

XOR이 아니라 **다른 논리 연산(예: OR, AND, NAND, NOR 등)을 사용하면 문제 발생**\
예를 들어, OR을 사용하면:

* `1 OR 1 = 1` 이므로, 1 + 1의 결과가 1이 되어 **잘못된 값이 나옴**.

이 때문에 XOR을 사용하지 않으면 **정확한 덧셈을 수행하기 위해 더 복잡한 논리 회로가 필요**하게 된다.

#### **3. 별도의 하드웨어가 필요한 이유**

만약 XOR을 사용하지 않고 덧셈을 수행하려면,

* 덧셈을 위한 맞춤형 논리 회로를 추가해야 함.
* 덧셈을 제대로 수행하려면 다른 조합의 논리 연산을 거쳐야 하므로, 연산 속도가 느려질 수 있음.
* XOR 없이 덧셈을 하려면, **더 많은 게이트(AND, OR, NAND 등)를 사용하여 원하는 결과를 만들도록 설계해야 함**.

{% hint style="warning" %}
이런 이유로 **XOR이 없는 덧셈 회로를 만들면 하드웨어 복잡성이 증가**하고, 기본적인 덧셈을 수행하는데 **더 많은 비용과 전력 소비가 필요**할 수 있다.
{% endhint %}

#### **4. XOR을 기반으로 한 반가산기와 전가산기**

컴퓨터의 `산술 논리 연산 장치(ALU, Arithmetic Logic Unit)`는 **XOR과 AND를 조합하여 덧셈 연산을 수행**한다.

1. **반가산기(Half Adder)**
   * 입력: A, B
   * **Sum(합)** = `A XOR B`
   * **Carry(올림)** = `A AND B`
2. **전가산기(Full Adder)**
   * 입력: A, B, 이전 자리에서 넘어온 Carry
   * **Sum(합)** = `(A XOR B) XOR Carry_in`
   * **Carry\_out(새로운 올림)** = `(A AND B) OR (Carry_in AND (A XOR B))`

XOR 없이 덧셈을 구현하려면 더 복잡한 논리 연산과 조합 회로가 필요해진다.

#### **5. 결론**

* XOR을 사용하면 **덧셈 연산을 가장 간단한 논리 회로로 구현**할 수 있다.
* 만약 XOR을 사용하지 않으면, **별도의 복잡한 논리 회로와 추가적인 하드웨어가 필요**해지며, 덧셈 연산 속도도 느려질 수 있다.
* 이 때문에 모든 CPU와 연산 회로에서는 **XOR을 기반으로 덧셈을 수행**하고 있다.

## 6. 실수를 표현하는 방법

> 지금까지는 <mark style="color:red;">정수를 2진수로 표현하는 방법</mark>을 살펴봤다. 그렇다면 실수는 어떻게 표현할 수 있을 까?

밑이 10인 실수에는 10진 소수점decimal point이 포함된다. 따라서 밑이 2인 경우, 실수를 표기하기 위해 `2진 소수점을 표현할 방법`이 필요하다.

여기서도 정수의 경우와 마찬가지로 문맥에 따라 실수를 표현하는 방법이 달라질 수 있다.

### 1) **2진수를 사용한 소수 표현: 고정소수점과 그 한계**

#### **1. 고정소수점(Fixed-Point) 표현법이란?**

{% hint style="info" %}
2진수를 사용해 소수를 표현하기 위해 <mark style="color:red;">2진 소수점의 위치를 임의로 정하는 방법</mark>이 있다. 소수점의 위치가 항상 일정하기 때문에 이런 방식을 `고정소수점 fixed-point 표현법`이라고 부른다
{% endhint %}

예를 들어, 4비트를 사용한다고 하면:

* **2비트는 정수 부분**
* **2비트는 소수 부분**

이렇게 정해진 비트 수를 사용해 고정된 위치에서 정수와 소수를 나눠 표현한다.

<figure><img src="https://498337729-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqKPDlntOwGZBfzPFGkYi%2Fuploads%2Fgueth1GTyb8IArdju3xD%2Fimage.png?alt=media&#x26;token=55658e14-30c2-4342-9024-b167ec9064c4" alt=""><figcaption></figcaption></figure>

<figure><img src="https://498337729-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqKPDlntOwGZBfzPFGkYi%2Fuploads%2F5Q79BT5Cgy9D0WYSuRJ6%2Fimage.png?alt=media&#x26;token=6b8fd695-aa32-411f-b148-5a5b6d25361c" alt=""><figcaption></figcaption></figure>



#### **2. 고정소수점의 특징**

1. **정수 표현 방식과 유사함** → 일반적인 2진수 표현에서 소수점을 미리 지정한 위치에 둔다.
2. **소수 부분은 2의 `거듭제곱`으로 표현됨** → 10진 소수(1/10, 1/100 등)와 달리, 2진 소수는 1/2, 1/4, 1/8, 1/16 등으로 표현된다.
3. **연산이 간단함** → 정해진 자리 수를 기준으로 덧셈, 뺄셈 연산을 수행할 수 있다.
4. **고정된 범위 내에서만 표현 가능** → 표현할 수 있는 값의 범위가 제한적

#### **3. 고정소수점의 한계**

1. **표현 가능한 수의 범위가 제한됨**
   * 비트 수가 고정되어 있어, 매우 큰 수나 매우 작은 수를 정확하게 표현하기 어렵다
   * 예를 들어, 4비트 고정소수점에서는 `0~3¾` 사이의 값만 표현 가능하므로, `4` 이상의 값이나 `1/8` 같은 더 작은 수는 표현할 수 없음.
2. **메모리 사용 비효율**
   * 더 정밀한 실수를 표현하려면 더 많은 비트가 필요하지만, 비트가 제한되어 있기 때문에 메모리 낭비가 발생할 수 있음.
   * 예를 들어, 32비트를 사용하여 실수를 표현한다고 할 때, `16비트 정수 + 16비트 소수`로 나눈다면, 작은 값도 32비트를 차지하게 됨.
3. **다양한 크기의 수 표현 어려움**
   * 플랑크 상수(6.63×10⁻³⁴)처럼 매우 작은 수와, 아보가드로 수(6.02×10²³)처럼 매우 큰 수를 함께 표현하기 어려움.
   * 이를 해결하려면 몇백 비트가 필요하므로 비효율적임.

쓸모 있는 범위의 실숫값을 표현하기 위해 <mark style="color:blue;">필요한 비트 개수가 너무 많기 때문에 범용 컴퓨터에서 이런 방식을 사용하는 경우는 드물다.</mark>

> 범용 컴퓨터는 일반적인 문제를 해결하기 위해 만들어진 컴퓨터라서 그런식으로 불린다.

#### **4. 고정소수점이 사용되는 곳**

고정소수점 표현법은 범용 컴퓨터에서는 잘 사용되지 않지만, **특정한 목적을 가진 컴퓨터(DSP, Digital Signal Processor)에서 사용**되기도 한다.

* **디지털 신호 처리(DSP)**: 오디오, 영상 처리 등의 작업에서 일정한 <mark style="color:blue;">정밀도를 유지하면서 연산 속도를 빠르게 하기 위해 사용</mark>됨.
* **임베디드 시스템(Embedded Systems)**: 메모리와 연산 자원이 제한된 환경에서는 고정소수점이 부동소수점보다 더 효율적임.

#### **5. 고정소수점의 대안: 부동소수점(Floating-Point)**

고정소수점 방식의 한계를 극복하기 위해 **부동소수점(Floating-Point) 표현 방식**이 등장했다.

{% hint style="info" %}
부동소수점 방식은 **소수점의 위치를 고정하지 않고 이동할 수 있도록 하는 방식**이다.
{% endhint %}

* 예를 들어, `1.23 × 10³`과 같은 형태로 수를 표현하면, <mark style="color:red;">큰 수나 작은 수도 효율적으로 표현</mark>할 수 있음.
* **IEEE 754 표준**을 따라 **32비트(단정도) 및 64비트(배정도) 부동소수점 방식**이 범용 컴퓨터에서 사용됨.

#### **6. 추가 배경 지식: 2진 소수 변환**

{% hint style="success" %}
고정소수점과 부동소수점 개념을 잘 이해하려면 **10진 소수를 2진 소수로 변환하는 방법**을 알아두는 것이 유용하다.
{% endhint %}

예를 들어, `0.625(10진수)`를 2진수로 변환하는 과정은 다음과 같다.

1. `0.625 × 2 = 1.25` → 정수 부분 `1`, 소수 부분 `0.25`
2. `0.25 × 2 = 0.50` → 정수 부분 `0`, 소수 부분 `0.50`
3. `0.50 × 2 = 1.00` → 정수 부분 `1`, 소수 부분 `0.00`

결과적으로, `0.625(10진수) = 0.101(2진수)`

* 하지만 10진수로 깔끔하게 표현되는 소수라도 <mark style="color:red;">2진수에서는 무한 반복</mark>되는 경우가 있음.
* 예를 들어, `0.1(10진수)`를 2진수로 변환하면 `0.0001100110011...(반복)` 형태로 끝없이 이어진다.
* 이런 반복 소수는 **부동소수점 연산에서 오차를 발생시키는 원인 중 하나**다.

### 2) 부동소수점 표현법

#### **1. 부동소수점이란?**

{% hint style="warning" %}
부동소수점(Floating-Point) 표현법은 **소수점 위치를 고정하지 않고 이동할 수 있도록 설계된 수 표현 방식**이다.
{% endhint %}

이는 과학적 표기법(Scientific Notation)을 2진수에 적용한 것으로, **큰 수와 작은 수를 효과적으로 표현**할 수 있다.\
과학적 표기법에서는 숫자를 **가수(Mantissa)와 지수(Exponent)**&#xB85C; 나눈다.\


예를 들어:

* `0.0012`를 과학적 표기법으로 표현하면 → `1.2 × 10⁻³`
* `120000`을 과학적 표기법으로 표현하면 → `1.2 × 10⁵`

2진법에서도 마찬가지로, 밑을 `2`로 하여 표현한다.\
예를 들어, `6.0`을 2진 부동소수점으로 표현하면 → `1.1 × 2²`

#### **2. 부동소수점의 구성 요소**

부동소수점 수는 **가수(Mantissa)와 지수(Exponent)**&#xB85C; 구성된다.

* **가수(Mantissa):** 실수 부분을 나타내며, **소수점 왼쪽에 한 자리만 있는 2진수로 정규화됨**.
* **지수(Exponent):** 2를 <mark style="color:red;">몇 번 거듭제곱해야 하는지</mark>를 나타냄.
* 예제 (4비트 부동소수점, 2비트 가수 + 2비트 지수)\
  가수 `1.1`, 지수 `10(₂) = 2(₁₀)`이면
* **실제 값 = 1.1 × 2² = 6.0(₁₀)**

#### **3. 부동소수점의 장점**

1. **더 넓은 범위의 수를 표현 가능**
   * 플랑크 상수(6.63 × 10⁻³⁴)부터 아보가드로 수(6.02 × 10²³) 같은 극단적인 값을 표현할 수 있음.
   * 고정소수점 방식과 달리, 매우 큰 수와 작은 수를 효율적으로 표현할 수 있음.
2. **소수점의 위치를 유동적으로 조절 가능**
   * 소수점이 움직이므로 다양한 크기의 수를 표현할 수 있음.
   * 예: `1.1 × 2³ = 8.0`, `1.1 × 2⁻² = 0.375`
3. **메모리 절약**
   * 필요한 만큼의 가수와 지수만 저장하면 되므로 고정소수점 방식보다 더 효율적임.

#### **4. 부동소수점의 단점**

<figure><img src="https://498337729-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqKPDlntOwGZBfzPFGkYi%2Fuploads%2Ftqx5183Mf0HJdnfIerXW%2Fimage.png?alt=media&#x26;token=1b5cb5bc-0394-4492-a5bb-0d8a0a6e4555" alt=""><figcaption></figcaption></figure>

<figure><img src="https://498337729-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqKPDlntOwGZBfzPFGkYi%2Fuploads%2F4Hgm94OsVgEdjrsxybQa%2Fimage.png?alt=media&#x26;token=d38572de-edb2-41ff-9758-d8bcca087d49" alt=""><figcaption></figcaption></figure>

1. **비효율적인 비트 사용**
   * 같은 값을 여러 개의 방법으로 표현할 수 있어 <mark style="color:red;">중복되는 비트 패턴이 발생.</mark>
   * 예를 들어 `1.0`과 `2.0`, `4.0` 같은 값은 여러 방법으로 표현 가능.
2. **정확도가 떨어질 수 있음**
   * 부동소수점 표현 방식은 <mark style="color:blue;">근사값을 저장하는 방식이라 정확도가 제한</mark>됨.
   * 2진수에서 표현할 수 없는 10진 소수(예: 0.1₁₀ → 0.0001100110011…₂ <mark style="color:blue;">무한 반복</mark>)가 존재함.
3. **연산 오류 발생 가능**
   * 지수가 커질수록 <mark style="color:blue;">가수의 한 패턴과 다른 패턴 사이의 값 차이가 커진다.</mark>
   * 예를 들어 `0.5 + 6.0` 같은 연산에서 `6.5`를 정확히 표현할 수 없는 문제가 발생할 수 있음.
   * 이러한 오류를 해결하기 위해 **수치 해석(Numerical Analysis)** 분야에서 연구가 이루어짐.

#### **5. IEEE 754 표준과 현대 부동소수점 표현**

{% hint style="success" %}
현대 컴퓨터에서는 **IEEE 754 부동소수점 표준**을 사용한다.
{% endhint %}

IEEE 754는 **단정도(32비트)와 배정도(64비트) 부동소수점 표현 방식**을 정의함.

* **32비트 단정도(Single Precision)**
  * 1비트: 부호(Sign)
  * 8비트: 지수(Exponent)
  * 23비트: 가수(Mantissa)
* **64비트 배정도(Double Precision)**
  * 1비트: 부호(Sign)
  * 11비트: 지수(Exponent)
  * 52비트: 가수(Mantissa)

IEEE 754 표준을 따르면 **부동소수점 연산의 정확성과 일관성을 유지할 수 있음**.

***

{% hint style="warning" %}
반면 12.00, 01.20, 00.12 같은 고정소수점 수에서 소수점 바로 왼 쪽의 수는 항상 일의 자리 숫자로 고정돼서 **고정 소수점**이다.&#x20;
{% endhint %}

> 소수점 왼쪽이 항상 일의 자리 숫자는 게 뭔소리일까? 12는 십의 자리인데

"소수점 왼쪽이 항상 일의 자리 숫자"라는 표현이 헷갈릴 수 있는데, 이는 **고정소수점 방식과 부동소수점 방식의 차이를 설명하는 맥락**에서 사용된 것이다.

**고정소수점에서의 소수점 위치**

고정소수점(Fixed-Point) 방식에서는 **소수점의 위치가 항상 정해져 있어서 변하지 않는다**.

예를 들어, 만약 소수점이 항상 **일의 자리 숫자(1자리) 왼쪽에 고정되어 있다**면, 다음과 같이 표현될 수 있다.

* `12.00`
* `01.20`
* `00.12`

이 경우, **소수점의 위치가 미리 정해져 있어서, 숫자가 변해도 소수점이 움직이지 않는다**.\
즉, `12`라는 숫자 자체가 아니라 **소수점 왼쪽 자릿수가 항상 같은 위치에 유지된다는 의미**이다.\
예를 들어, 10진수 기준으로 **소수점이 일의 자리 숫자 바로 오른쪽에 고정된다면**, 항상 다음과 같이 표현된다.

* `3.45`
* `1.23`
* `0.12`
* `45.67` (여기서는 십의 자리도 포함하지만, 소수점 바로 왼쪽은 5라는 일의 자리)

즉, **소수점의 위치가 항상 같은 곳에 있고, 소수점 왼쪽이 일의 자리 숫자로 유지된다는 의미**이다.

#### **2. 부동소수점에서의 소수점 위치 변화**

반면 **부동소수점(Floating-Point) 방식에서는 소수점이 유동적으로 움직일 수 있다**.\
이는 `과학적 표기법(Scientific Notation)`과 같은 방식으로 숫자를 표현하기 때문이다.

예를 들어, 1.2라는 가수를 사용하여 다른 숫자들을 표현하면

* `1.2 × 10⁰ = 1.2`
* `1.2 × 10¹ = 12`
* `1.2 × 10² = 120`
* `1.2 × 10⁻¹ = 0.12`

같은 `1.2`라는 숫자라도, **소수점의 위치가 변하면서 숫자의 크기가 달라질 수 있다**.

이와 마찬가지로, 2진수 부동소수점에서도 **소수점이 가수(Mantissa)와 지수(Exponent)에 의해 달라지는 것**이다.

* `1.10 × 2³ = 11.0₂ (10진수 6)`
* `1.10 × 2⁻² = 0.0110₂ (10진수 0.375)`
* `1.10 × 2⁵ = 110000.0₂ (10진수 48)`

즉, **고정소수점에서는 숫자가 커져도 소수점의 위치가 일정하지만**,\
**부동소수점에서는 숫자의 크기에 따라 소수점의 위치가 바뀐다**는 차이가 있다.

#### **3. 요점 정리**

* **고정소수점**에서는 **소수점의 위치가 고정**되어 있어서 **소수점 왼쪽 자릿수가 항상 같은 위치에 존재한다**.
  * 즉, 특정한 자리수(예: 일의 자리)에서 소수점이 고정되어 변하지 않는다.
* **부동소수점**에서는 **소수점이 숫자의 크기에 따라 이동**할 수 있기 때문에, 소수점 왼쪽 숫자가 항상 같은 자리에 있지 않는다.
  * 즉, **같은 숫자라도 소수점이 움직이므로 다양한 크기의 값을 표현할 수 있다**.

따라서 소수점 왼쪽이 항상 일의 자리 숫자다라는 말은,\
<mark style="color:red;">고정소수점에서는 소수점이 항상 같은 위치에 있어서, 숫자의 자릿수가 변해도 소수점 왼쪽의 숫자 위치는 일정하다는 의미로 이해</mark>하면 된다.

***

#### | 결론

* 부동소수점 표현법은 **소수점의 위치를 고정하지 않고 유동적으로 조절하는 방식**이다.
* 고정소수점보다 훨씬 넓은 범위의 숫자를 표현할 수 있어, 현대 컴퓨터에서 널리 사용된다.\
  하지만 **정확도의 한계**와 **연산 오류 가능성**이 있으며, 이를 해결하기 위해 IEEE 754 표준이 도입되었다.
* 부동소수점 연산을 다룰 때는 **반올림 오차, 정밀도 손실, 수치 해석 기법** 등을 고려해야 한다.

이제 부동소수점 개념이 이해되었으면,

* **IEEE 754 부동소수점 표준의 내부 구조와 동작 방식**
* **부동소수점 연산에서 발생하는 오차와 그 해결 방법**
* **컴퓨터에서 실수 연산을 다룰 때 주의할 점**

등을 배우면 더욱 깊이 있는 이해가 가능하다. 🚀

### 3) IEEE 부동소수점 수 표현

#### **1. IEEE 754 부동소수점 표준의 개요**

{% hint style="info" %}
IEEE 754는 컴퓨터에서 **실수를 부동소수점 방식으로 표현하고 연산하는 표준**이다.
{% endhint %}

이 표준은 **단정도(32비트)와 배정도(64비트) 부동소수점**을 정의하며, 부동소수점 연산의 정확성을 높이기 위한 여러 기법이 포함되어 있다.

부동소수점은 표 1-8보다 더 많은 비트를 사용하며, 가수와 지수에 대해 **각각 부호 비트를 사용**한다  지수에 대한 부호 비트는 **지수의 비트 패턴에 감춰져 있다.**&#x20;

{% hint style="success" %}
&#x20;낭비되는 비트 조합을 최소화하고 반올림을 쉽게 하기 위한 여러 가지 트릭이 사용된다.&#x20;
{% endhint %}

IEEE 754라는 표준은 이 모든 기능을 정의한다.



#### **2. 부동소수점 수의 구조 (32비트 기준)**

| 부호 (Sign) | 지수 (Exponent)        | 가수 (Mantissa)         |
| --------- | -------------------- | --------------------- |
| 1비트       | 단정도: 8비트 / 배정도: 11비트 | 단정도: 23비트 / 배정도: 52비트 |

* **1비트 (부호, Sign)** → `0`이면 양수, `1`이면 음수
* **8비트 (지수, Exponent)** → 2의 거듭제곱을 나타내며, **Bias를 적용**하여 부호 비트 없이 표현
* **23비트 (가수, Mantissa)** → 유효숫자로, **정규화(normalization) 기법**을 적용하여 저장 공간을 절약

#### **3. 부동소수점 수의 계산 공식**

> 실제 값=(−1)부호×(1+가수)×2(지수−Bias)\text{실제 값} = (-1)^{\text{부호\}} \times (1 + \text{가수}) \times 2^{(\text{지수} - \text{Bias})}

* 단정도(32비트) → Bias: **127**
* 배정도(64비트) → Bias: **1023**

**예제**: `0 10000001 10100000000000000000000` (단정도 32비트)

* 부호: `0` (양수)
* 지수: `10000001₂ = 129`, 실제 지수 = `129 - 127 = 2`
* 가수: `1.101₂ = 1 + 0.5 + 0.125 = 1.625`
* 값: `1.625 × 2² = 6.5`

#### **2. 정밀도를 높이기 위한 기술**

IEEE 754는 **똑같은 비트를 사용하면서도 최대한 정밀도를 높이는 다양한 기법**을 적용한다.

<figure><img src="https://498337729-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqKPDlntOwGZBfzPFGkYi%2Fuploads%2FkzkghSSAfp5T1XIhA0BW%2Fimage.png?alt=media&#x26;token=57da9dc7-52c0-4cb0-ae1b-5bba9a6b1ba4" alt=""><figcaption><p>S가 부호이며, 두 형태 모두 가수에 대한 부호를 사요ㅇㅎㅏㄴ다.</p></figcaption></figure>

**(1) 정규화(Normalization)**

{% hint style="warning" %}
**가수의 왼쪽(맨 앞) 비트가 항상 1이 되도록 조정**하여 **불필요한 0을 제거**하고 비트 공간을 절약.
{% endhint %}

* **예제:** `0.01101 × 2⁵` → `1.101 × 2²`
  * 원래는 `01101.0000₂` 이지만, **왼쪽 첫 번째 1이 가수의 시작이 되도록 소수점을 이동하고 지수를 조정**.

**(2) 암시적 1비트 (Hidden Bit)**

{% hint style="warning" %}
**가수의 맨 앞 비트는 항상 1이므로 저장하지 않고 생략**, 대신 필요한 추가 정보를 저장할 수 있도록 비트를 절약
{% endhint %}

* 단정도에서는 23비트 가수지만 **실제로는 24비트(1비트가 암시적 1비트로 존재)**.
* 디지털 이큅먼트 사DEC, Digital Equipment Corporation에서 고안한 것
  * 가수의 맨 왼쪽 비트가 1이라는 사실을 알고 있으므로 이를 생략하는 것

> 이로 인해 가수에 1비트를 더 사용할 수 있다

IEEE 754의 세부 사항을 모두 알 필요는 (아직은) 없다. 하지만 **두 가지 부동소수점 수가 자주 쓰인다는 사실을 알아둬야 한다.**



#### **3. 단정도(32비트) 기본 정밀도 vs 배정도(64비트) 2배 정밀도**

| 구분        | 단정도 (Single Precision, 32비트) | 배정도 (Double Precision, 64비트) |
| --------- | ---------------------------- | ---------------------------- |
| 부호 비트     | 1비트                          | 1비트                          |
| 지수 비트     | 8비트 (Bias = 127)             | 11비트 (Bias = 1023)           |
| 가수 비트     | 23비트 (24비트 효과)               | 52비트 (53비트 효과)               |
| 정밀도       | 약 7자리 (10진수)                 | 약 15자리 (10진수)                |
| 표현 가능한 범위 | ±10³⁸ 정도                     | ±10³⁰⁸ 정도                    |
| 메모리 사용량   | 적음 (일반적인 연산에 적합)             | 큼 (과학 계산, 금융 연산에 적합)         |

그림에서 2배 정밀도 수가 기본 정밀도 수보다 지수가 3비트 더 크다는 점을 볼 수 있다.&#x20;

> 따라서 지수의 범위 는 8배 더 크다.&#x20;

`2배 정밀도 수`는 기본 정밀도 수보다 가수가 29비트 더 크다. **따라서 정밀도도 훨씬 더 크다.** 하지만 이런 모든 장점은 <mark style="color:red;">비트를 2배나 더 많이 사용한다는 비용을 지불하고 얻은 것</mark>이다.

#### **4. IEEE 754의 추가적인 특성**

> 지수에 대해 부호 비트가 따로 존재하지 않는다.

IEEE 754 를 설계한 사람들은 지수 비트가 모두 0이거나 1인 경우에 특별한 의미를 갖게 하고, 실제 지숫 값은 나머지 비트 패턴에 집어넣고 싶었다. 그래서IEEE 754는 **특별한 비트 패턴을 사용하여 특정한 연산 결과를 처리할 수 있도록 설계**되었다.

**(1) 편향된(Biased) 지수**

* 지수 값에 **Bias(편향값)를 더해 부호 비트를 없애고, 정렬을 쉽게 함**.
* 단정도에서는 Bias = **127**, 배정도에서는 Bias = **1023** 사용.
  * `127(01111111₂)` → 실제 지수 `0`
  * `1(00000001₂)` → 실제 지수 `-126`
  * `254(11111110₂)` → 실제 지수 `+127`

**(2) 0으로 나누는 경우의 처리**

* IEEE 754는 **0으로 나누는 연산을 수행할 때&#x20;**<mark style="color:blue;">**양/음의 무한대(∞)를 표현**</mark>**하는 특별한&#x20;**<mark style="color:blue;">**비트 패턴**</mark>을 제공.
  * `+∞`, `-∞`을 명확히 정의하여 **에러 처리를 쉽게 만듦**.

**(3) NaN (Not a Number)**

* `0/0`, `√(-1)` 같은 **정의되지 않은 연산이 발생하면 NaN(Not a Number)을 반환**.
* NaN 값이 포함된 계산은 전파되어, 후속 연산에서도 NaN을 유지함.
* 부동소수점 수로 계산을 하던 도중에 NaN 값이 생기면 뭔가 잘못된 산술 연산을 수행했다는 뜻

{% hint style="success" %}
이런 특별한 비트 패턴들은 앞에서 이야기한 **특별한 지숫값**(모든 비트가 0이거나 모든 비트가 1인 지수)을 사용
{% endhint %}

#### **5. 부동소수점 시스템의 한계와 주의할 점**

부동소수점 연산은 **비트 수가 제한된 환경에서 실수를 표현해야 하므로, 오차가 발생할 수 있다**.

**(1) 표현할 수 없는 값**

* 10진수 `0.1`을 2진수로 변환하면 무한 반복(0.0001100110011...)되므로, **근사값**으로 저장됨.
* 이로 인해 `0.1 + 0.2 ≠ 0.3` 같은 연산 오차가 발생할 수 있음.

**(2) 반올림 오차 (Rounding Error)**

* 저장할 수 있는 비트 수가 제한되므로 **반올림이 발생**하고, **작은 숫자가 더해질 때 정밀도가 떨어질 수 있음**.

**(3) 연산 순서에 따른 오차**

* **(A + B) + C ≠ A + (B + C)** 가 될 수 있음.
* 큰 숫자와 작은 숫자를 더할 때, 작은 숫자가 반올림으로 인해 손실될 수도 있음.

#### **6. 부동소수점 오차 해결 방법**

부동소수점 연산의 오차를 줄이기 위해 여러 기법을 사용할 수 있다.

**(1) Kahan Summation Algorithm**

* 작은 값이 반올림으로 손실되는 문제를 해결하는 알고리즘.

**(2) `decimal` 모듈 사용 (Python)**

```python
from decimal import Decimal
print(Decimal('0.1') + Decimal('0.2'))  # 정확히 0.3 반환
```

**(3) 정수 연산 활용**

* 금융 연산에서는 소수를 사용하지 않고 **정수 단위로 변환 후 연산**하는 것이 일반적임.

```python
cents = 100  # 1달러 = 100센트
total = cents * 1.07  # 7% 세금
print(f"{total / 100:.2f} USD")  # 정확한 계산
```

#### **7. 결론**

* IEEE 754 부동소수점 표준은 실수를 표현하는 방식으로, 부호(1비트), 지수(8비트), 가수(23비트)로 구성됨.
* Bias를 적용한 지수 표현과 정규화된 가수를 사용하여 저장 공간을 효율적으로 활용함.
* **단정도(32비트)**&#xB294; 일반적인 연산에 적합하고, **배정도(64비트)**&#xB294; 높은 정밀도가 필요한 과학 및 금융 연산에 적합.
* 부동소수점 연산에서는 표현할 수 없는 값, 반올림 오차, 연산 순서에 따른 오차가 발생할 수 있음.
* Kahan Summation, `decimal` 모듈 사용, 정수 연산 활용 등의 방법으로 오차를 줄일 수 있음.

#### **8. 컴퓨터에서 실수 연산을 다룰 때 주의할 점**

**(1) 비교 연산에서 `==` 사용 금지**

* `if (x == 0.1)` 같은 비교는 오차 때문에 잘못된 결과를 낼 수 있음.
*   대신 **허용 오차(ε)를 활용한 비교**를 해야 함.

    ```python
    EPSILON = 1e-9
    if abs(x - 0.1) < EPSILON:
        print("x는 0.1과 거의 같다")
    ```

**(2) 누적 오차 고려**

* 반복 연산이 많아질수록 오차가 누적될 수 있으므로, **정밀도를 고려해야 함**.

**(3) 정확한 계산이 필요한 경우 정수 연산 사용**

*   금융 계산에서는 **소수를 직접 사용하지 않고, 정수 단위(예: 센트 단위)로 변환**하는 것이 일반적임.

    ```python
    cents = 100  # 1달러 = 100센트
    total = cents * 1.07  # 7% 세금
    print(f"{total / 100:.2f} USD")  # 정확한 계산
    ```

**(4) 알고리즘 설계 시 오차를 감안한 전략 필요**

* 수치 해석(Numerical Analysis) 기법을 활용하여 **부동소수점 오차를 최소화하는 알고리즘을 선택**해야 함.

## 7. 2진 코드화한 10진수 시스템 : BCD(Binary-Coded Decimal)

**1. BCD란?**

{% hint style="warning" %}
BCD(Binary-Coded Decimal)는 **4비트를 사용하여 10진 숫자(0\~9)를 개별적으로 표현하는 방식**이다.
{% endhint %}

즉, **각 10진 자리(일의 자리, 십의 자리 등)를 4비트 이진수로 변환하여 저장**한다.

**예제:**

* **10진수 12**
  * 일반적인 2진수 표현: `1100₂`
  * BCD 표현: `0001 0010₂` (`1`은 십의 자리, `2`는 일의 자리)

> BCD 방식은 **사람이 읽고 해석하기 쉬운 장점**이 있어, **디지털 디스플레이나 센서 데이터 처리** 등에 사용된다.

**2. BCD의 장점**

1. **10진수와의 직관적인 호환성**
   * 사람에게 익숙한 10진수와 직접적으로 매핑되므로, **디지털 디스플레이 장치에서 사용하기 편리**함.
   * 예를 들어, `127`을 BCD로 표현하면 `0001 0010 0111`로 변환되며, 각 4비트 단위로 10진수를 쉽게 읽을 수 있음.
2. **디지털 기기에서 유용**
   * **디지털 시계, 계산기, 계측기, 센서 등**에서 **BCD를 사용하면 숫자를 그대로 출력하기 쉬움**.
   * 예를 들어, LCD 디스플레이에서 숫자를 표시할 때, **BCD를 사용하면 변환 과정이 간단**해짐.

**3. BCD의 단점**

1. **비트 낭비**
   * 4비트는 `0000₂`(0)부터 `1111₂`(15)까지 **16가지 값을 표현할 수 있지만, BCD에서는 10진수 0\~9까지만 사용**.
   * 즉, **6가지 조합(`1010₂`\~`1111₂`)은 사용되지 않으며,** 전체 비트의 37.5%가 낭비됨.
2. **연산 비효율성**
   * 일반적인 2진수 연산과 다르게, **BCD 연산(덧셈, 뺄셈 등)은 별도의 보정이 필요**함.
   * 예를 들어, BCD 덧셈에서 `9 + 1 = 10`이 되면, **1**0을 BCD로 변환(`0001 0000₂`)하는 추가 과정이 필요.
   * 따라서 **CPU가 직접 BCD 연산을 지원하지 않으면, 소프트웨어적으로 처리해야 하는 부담이 생김**.

**4. BCD의 사용 감소**

{% hint style="danger" %}
과거 일부 컴퓨터들은 **BCD를 직접 지원하는 명령어를 제공**했지만, **오늘날에는 거의 사용되지 않음**.\
그 이유는 **일반적인 2진수 표현보다 비효율적이기 때문**이다.
{% endhint %}

* **과거:**
  * 컴퓨터 성능이 낮고, 비트 비용이 높았을 때 **디지털 디스플레이 장치와의 호환성 때문에 BCD가 사용됨**.
  * 예를 들어, 초창기 **IBM 메인프레임** 일부 모델에서는 BCD를 하드웨어적으로 지원.
* **현재:**
  * 비트 비용이 낮아졌으며, **BCD의 비효율성이 크기 때문에 대부분 2진수 연산으로 대체됨**.
  * 일부 센서나 디지털 디스플레이 장치에서 BCD가 사용되지만, **연산 처리는 대부분 일반적인 2진수 방식으로 변환하여 수행**.

## 8. 2진수를 다루는 쉬운 방법

> 사람들은 2진수를 더 읽기 쉽게 표현할 수 있는 방법을 고안해냈다.

### 1) 8진 표현법

{% hint style="warning" %}
8진 표현법은 **2진수 비트들을 3개씩 그룹으로 묶는** 아이디어
{% endhint %}

<figure><img src="https://498337729-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqKPDlntOwGZBfzPFGkYi%2Fuploads%2Fe5NDYtmdkJ30kXFqb9cq%2Fimage.png?alt=media&#x26;token=a0ca154b-8720-44c8-a450-378a7fcc35a8" alt=""><figcaption></figcaption></figure>

100이라는 2진 값을 8진 숫자로 바꾸기 위해서는 (1×22 )+ (0×21 ) + (0×20 ) = 4라는 식으로 계산

### 2) 16진 표현법

현재 널리 쓰이고 있는 진법으로 밑이 16이라는 뜻이다.

{% hint style="warning" %}
현재 널리 쓰이고 있는 이유는 컴퓨터 내부가 <mark style="color:red;">8비트의 배수로</mark>를 사용해 만들어지기 떄문이다.&#x20;
{% endhint %}

8비트의 배수는  4(16진수의 한 자리의 비트 수)로 균일하게 나눠지지만 3(8진수의 한 자리의 비트 수)로는 나눠지지 않는다.

10진 숫자 기호 중 16진수를 표현하라면 6개가 더 필요해서 abcdef라는 기호가 숫자를 표현하기로 한 것이다.

<figure><img src="https://498337729-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqKPDlntOwGZBfzPFGkYi%2Fuploads%2F8AwPmmOxABO0qw2s6zav%2Fimage.png?alt=media&#x26;token=a1cd0d45-8ebb-4422-81e8-4b6f99ff86cf" alt=""><figcaption></figcaption></figure>

이 예제에서 비트를 4개씩 그룹으로 나눈다.&#x20;

<figure><img src="https://498337729-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqKPDlntOwGZBfzPFGkYi%2Fuploads%2FfAM98nYojj5h9iwvVmyO%2Fimage.png?alt=media&#x26;token=3f3cb75b-7884-4796-863d-3d36b4f6d351" alt=""><figcaption></figcaption></figure>

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

수를 표현하는 방법은 원래는 아래 첨자로 나타내서 일 수 있지만 컴퓨터 키보드로는 입력하기 불편하기에 **입력하기 편한 일관성 있는 표기법**을 사용하면 좋다.

**✅ 진법별 숫자 표기 규칙**

| 진법                     | 접두사(Prefix)                     | 예시 (표기법) | 10진수 변환 값    |
| ---------------------- | ------------------------------- | -------- | ------------ |
| **8진수 (Octal)**        | `0` (0으로 시작)                    | `017`    | `15 (10진수)`  |
| **10진수 (Decimal)**     | 없음 (1\~9로 시작)                   | `123`    | `123 (10진수)` |
| **16진수 (Hexadecimal)** | `0x`                            | `0x12f`  | `303 (10진수)` |
| **2진수 (Binary)**       | `0b` _(C++, Python 등 일부 언어 지원)_ | `0b1010` | `10 (10진수)`  |

***

**📌 설명 및 특징**

1. **8진수 (Octal)**
   * 숫자가 `0`으로 시작하면 8진수로 간주됨.
   * 예: `017` → 10진수로 변환하면 `1×8^1 + 7×8^0 = 8 + 7 = 15`
2. **10진수 (Decimal)**
   * 일반적으로 사용되는 숫자 시스템으로, 1\~9로 시작하는 숫자는 10진수로 해석됨.
   * 예: `123` → 그대로 `123` (10진수)
3. **16진수 (Hexadecimal)**
   * `0x`를 앞에 붙이면 16진수로 표현됨.
   * 예: `0x12f` → 10진수 변환 `1×16^2 + 2×16^1 + 15×16^0 = 256 + 32 + 15 = 303`
4. **2진수 (Binary)**
   * 일부 프로그래밍 언어에서 `0b` 접두사를 사용하여 2진수를 표현함.
   * 예: `0b1010` → 10진수 변환 `1×2^3 + 0×2^2 + 1×2^1 + 0×2^0 = 8 + 0 + 2 + 0 = 10`

**⚠️ 주의할 점**

* **0이 단독으로 사용될 경우, 8진수인지 10진수인지 구분할 필요가 없음** → 어차피 값은 `0`
* 대부분의 프로그래밍 언어는 **2진수 표기를 기본적으로 제공하지 않음** (C++, Python 등 일부 언어만 `0b` 지원)

**🚀 결론**

* **프로그래밍에서 숫자의 진법을 정확히 이해하고 사용해야 오류를 방지할 수 있음.**
* **8진수는 사용이 줄어들고 있으며, 현대 프로그래밍에서는 주로 10진수와 16진수를 사용.**
* **16진수는 메모리 주소, 색상 코드, 비트 연산 등에서 널리 활용됨.**
* **2진수는 직접적으로 사용할 일은 적지만, 일부 언어에서는 `0b` 접두사로 표현 가능.**

✅ **즉, 숫자의 형태와 접두사를 보고 진법을 올바르게 해석하는 것이 중요하다!**

## 9. 비트 그룹의 이름

#### **컴퓨터의 비트 조직과 데이터 크기 단위 정리**

#### **1️⃣ 비트의 조직화**

* 컴퓨터는 **무작위로 비트를 배치하지 않음** → 컴퓨터를  설계하는 사람은비용을 고려하여 비트 개수와 조직을 결정
* **비트는 너무 작아서 직접 사용하기 어렵기 때문에, 더 큰 단위로 묶어서 사용**
* 과거 다양한 비트 단위가 존재했으나 **현재는 8비트(바이트, byte)가 표준**
* **예시:**
  * **Honeywell 6000** → 36비트 단위, 18비트/9비트/6비트로 분할 가능
  * **DEC PDP-8** → 12비트 단위 사용
  * **현재** → **8비트(1바이트, byte)가 표준**

#### **2️⃣ 비트 묶음 단위**

| **이름**                 | **비트 개수** | **설명**         |
| ---------------------- | --------- | -------------- |
| **니블(Nibble)**         | 4비트       | 바이트의 절반        |
| **바이트(Byte)**          | 8비트       | 문자, 데이터의 기본 단위 |
| **하프 워드(Half Word)**   | 16비트      | 2바이트(16비트)     |
| **워드(Word)**           | 32비트      | 4바이트(32비트)     |
| **더블 워드(Double Word)** | 64비트      | 8바이트(64비트)     |

* **워드(Word)**: 컴퓨터가 가장 자연스럽게 처리할 수 있는 **비트 묶음 크기**
  * 자연스럽게 쓸 수 있다는 말은 컴퓨터가 **빠르게 처리할 수 있는 가장 큰 덩어리**
  * 예: **PDP-11** → 내부적으로 16비트 사용
  * `int` 자료형의 크기는 컴퓨터의 워드 크기에 따라 달라짐
  * C/C++에서는 `uint8, int16, int32, DWORD, INT32` 같은 타입을 제공

#### **3️⃣ 데이터 크기 단위 (전통적인 vs 표준)**

> **킬로(kilo), 메가(mega), 기가(giga) 등의 단위는 원래 10진수(10^x)였지만, 컴퓨터에서는 2진수(2^x)로 사용됨.**

**📌 기존(전통적인) 컴퓨터 단위**

> 컴퓨터 엔진니어들은 용어를 빌려와서 사용하되 의미를 약간 바꿔서 밑이 10이 아니라 2인 값을 표현했으며, 실제로는 1000을 뜻하지 않고, **밑이 2면서 1000에 가장 가까운 수라 1024이다.**

| **단위**         | **2진수 값**                     | **10진수 값 (디스크 크기 표기)**         |
| -------------- | ----------------------------- | ------------------------------ |
| **킬로바이트 (KB)** | `2¹⁰ = 1,024` 바이트             | `10³ = 1,000` 바이트              |
| **메가바이트 (MB)** | `2²⁰ = 1,048,576` 바이트         | `10⁶ = 1,000,000` 바이트          |
| **기가바이트 (GB)** | `2³⁰ = 1,073,741,824` 바이트     | `10⁹ = 1,000,000,000` 바이트      |
| **테라바이트 (TB)** | `2⁴⁰ = 1,099,511,627,776` 바이트 | `10¹² = 1,000,000,000,000` 바이트 |

{% hint style="info" %}
항상 문맥이 중요한데 때때로 이런 말들이 밑이 10인 용어를 뜻할 때도 있었다.
{% endhint %}

* **문제:** 일부 제조사(특히 디스크 크기 표기)에서 10진수(1,000) 단위를 사용하여 혼동 발생\
  → 예: 1TB 하드디스크의 실제 크기가 운영체제에서 931GiB로 보이는 이유

#### **4️⃣ IEC 표준 단위 (정확한 표현)**

> **기존 단위(킬로, 메가, 기가 등)의 혼동을 방지하기 위해 새로운 단위가 도입됨.**

| **새로운 단위 (IEC 표준)** | **2진수 값 (정확한 표현)**            | **기존 단위 (혼용된 표현)** |
| ------------------- | ----------------------------- | ------------------ |
| **키비바이트 (KiB)**     | `2¹⁰ = 1,024` 바이트             | `1KB (전통적 의미)`     |
| **메비바이트 (MiB)**     | `2²⁰ = 1,048,576` 바이트         | `1MB`              |
| **기비바이트 (GiB)**     | `2³⁰ = 1,073,741,824` 바이트     | `1GB`              |
| **테비바이트 (TiB)**     | `2⁴⁰ = 1,099,511,627,776` 바이트 | `1TB`              |

* IEC 단위(키비, 메비, 기비)는 정확한 **2진수 기반 크기**를 의미함.
* 점점 더 많은 기술 문서 및 운영체제에서 **IEC 표준(KiB, MiB, GiB, TiB)** 를 사용 중.

#### **5️⃣ 문자(Character)와 바이트의 관계**

* **과거:** 문자(Character) = 1바이트(Byte)\
  → ASCII(7비트, 1바이트로 표현 가능) 사용
* **현재:** 다국어 지원을 위해 **문자가 1바이트로 표현되지 않는 경우 증가**\
  → **UTF-8, UTF-16, UTF-32 등 멀티 바이트 문자 인코딩 등장**
  * **예:** 한글 "가" → UTF-8에서는 3바이트 사용

#### **📌 결론**

* `비트`는 작은 단위이므로, 컴퓨터는 이를 더 큰 단위(니블, 바이트, 워드 등)로 조직하여 사용.
* 현재 대부분의 컴퓨터는 **8비트(1바이트)를 기본 단위**로 사용.
* 데이터 크기 단위(킬로, 메가, 기가 등)는 원래 10진수였으나, 컴퓨터에서는 2진수(1024 단위)로 사용됨.
* IEC 표준(KiB, MiB, GiB, TiB)이 도입되었으나, 기존 단위와 혼용되는 경우가 많아 주의해야 함.
* 문자는 1바이트로 표현되지 않을 수 있으며, UTF-8과 같은 멀티 바이트 인코딩이 널리 사용됨.

{% hint style="danger" %}
컴퓨터에서 데이터 크기를 다룰 때는 **반드시 2진수와 10진수의 차이를 이해하고 문맥을 고려해야 한다.**
{% endhint %}

## 10. 텍스트 표현

> 수를 사용해 문자나 키보드에 있는 다른 기호 등을 표현하는 방법

### 1) 아스키 코드

#### **💡 아스키(ASCII) 코드와 제어 문자 정리**

***

### **1️⃣ ASCII(아스키) 코드란?**

> **ASCII (American Standard Code for Information Interchange, 미국 표준 코드)**\
> **키보드 문자 및 기호를 7비트 숫자로 표현하는 표준 인코딩 방식**\
> **1963년부터 표준화 → 현재도 기본적인 문자 인코딩 방식으로 사용됨**

* **각 문자(알파벳, 숫자, 특수 기호)에 7비트(0\~127)의 숫자 할당**
* **예제:**
  * **A** → 10진수 `65`, 16진수 `0x41`, 8진수 `0101`
  * **B** → 10진수 `66`, 16진수 `0x42`
  * **공백(Space, SP)** → 10진수 `32`, 16진수 `0x20`
* **경쟁했던 다른 인코딩 방식:**
  * **IBM의 EBCDIC(엡시딕, Extended Binary-Coded Decimal Interchange Code) ->** ‘BCD’는 앞에서 살펴본 2진 코드화한 10진수를 뜻함
  * 하지만 ASCII가 표준이 됨.

### **2️⃣ ASCII 코드표 (일부 주요 문자 예시)**

| **10진수** | **16진수** | **문자** | **설명**     |
| -------- | -------- | ------ | ---------- |
| 32       | 20       | `SP`   | 공백(Space)  |
| 48       | 30       | `0`    | 숫자 0       |
| 49       | 31       | `1`    | 숫자 1       |
| 65       | 41       | `A`    | 대문자 A      |
| 66       | 42       | `B`    | 대문자 B      |
| 97       | 61       | `a`    | 소문자 a      |
| 98       | 62       | `b`    | 소문자 b      |
| 126      | 7E       | `~`    | 물결 기호      |
| 127      | 7F       | `DEL`  | 삭제(Delete) |

> **ASCII 코드의 문자들은 7비트(0\~127) 내에서 표현됨.**

#### **3️⃣ 제어 문자(Control Characters)**

> **ASCII 코드 중 화면에 출력되지 않고, 장치를 제어하는 문자들**\
> **통신, 데이터 처리, 프린터 제어 등에 사용됨**

#### **🛠 주요 제어 문자**

| **기호**      | **10진수** | **설명**                  |
| ----------- | -------- | ----------------------- |
| **NUL**     | 0        | 널(null) 문자              |
| **BEL**     | 7        | 벨(Bell) → 소리 알림         |
| **BS**      | 8        | 백스페이스(Backspace)        |
| **HT**      | 9        | 가로 탭(Horizontal Tab)    |
| **NL (LF)** | 10       | 새 줄(Line Feed)          |
| **CR**      | 13       | 캐리지 리턴(Carriage Return) |
| **ESC**     | 27       | 이스케이프(Escape)           |
| **DEL**     | 127      | 삭제(Delete)              |

#### **예제:**

* **`LF(새 줄)` + `CR(캐리지 리턴)`**
  * 윈도우: `CR + LF` (줄바꿈 → `\r`)
  * 유닉스/리눅스: `LF` ()
  * 맥OS (구버전): `CR` ()

#### **4️⃣ ASCII의 한계와 확장**

* ASCII는 **영어 기반(128개 문자)** → 한글, 일본어, 중국어 표현 불가
* 확장 ASCII(8비트, 256개 문자) 등장 → **ISO-8859, Windows-1252**
* 이후 **UTF-8(가변 길이, 유니코드 지원) 등장 → 국제 표준으로 자리 잡음**

### 2) **🔍** 다른 표준의 진화 : 아스키(ASCII)와 유니코드(Unicode)의 발전 과정

#### **아스키(ASCII)**

* **초기 컴퓨터**에서 사용된 문자 인코딩 방식.
* **7비트(0\~127)** 로 구성되어 **영어 알파벳, 숫자, 특수 문자**만 표현 가능.
* **미국에서 개발되었으며**, 대부분의 초기 컴퓨터가 미국산 또는 영국산이었기 때문에 문제없었음.

#### **아스키의 한계와 국제 문자 지원**

{% hint style="danger" %}
컴퓨터가 **전 세계적으로 보급됨**에 따라 영어 이외의 문자(예: 유럽어, 아시아 문자)를 지원해야 하는 문제가 발생.
{% endhint %}

**ISO 표준 확장**

* **ISO-646** : 아스키를 확장하여 일부 유럽 언어의 **액센트(é, à, ü 등) 및 발음 구별 기호** 추가.
* **ISO-8859** : 다양한 언어(서유럽어, 동유럽어, 아랍어 등)를 지원하는 8비트 문자 세트.

**각국의 문자 인코딩**

* **JIS X 0201** : 일본어 표현을 위한 일본 산업 표준(JIS).
* **KS C 5601** : 한국어 표현을 위한 한국 문자 코드 표준.
* **GB2312** : 중국어 지원을 위한 중국 문자 코드.

#### **📌 유니코드(Unicode) 등장**

각 국가마다 서로 다른 문자 인코딩 방식을 사용하다 보니 **문자 간 호환성이 떨어지는 문제** 발생.

**💡 유니코드의 등장**

{% hint style="success" %}
**유니코드는 과거의 여러 문자 인코딩 문제를 해결하고, 전 세계 언어와 기호(이모지 포함)를 통합하는 표준이다.**
{% endhint %}

* **16비트(0\~65535) 기반**의 새로운 문자 표준 도입.
* 기존 **아스키(7비트)보다 훨씬 많은 문자**를 표현 가능하여 **모든 언어를 지원**할 수 있도록 설계됨.
* 초기에는 **16비트면 충분하다고 생각했지만**, 예상보다 많은 언어와 문자(한자, 이모지 등)가 추가됨.

**유니코드 확장 (21비트)**

* 현재 유니코드는 **21비트(1,112,064개 코드)** 까지 확장됨.
* 현대에는 **고양이 이모티콘 🐱, 다양한 기호(⚡, 🎵, 🏆) 등도 포함**되어 있음.

#### **📌 정리**

1. **아스키(ASCII)** : 영어만 표현 가능 (7비트)
2. **ISO 표준(ISO-646, ISO-8859 등)** : 유럽 언어 및 일부 확장
3. **각국 문자 인코딩(JIS, KS C 5601 등)** : 일본어, 한국어, 중국어 지원
4. **유니코드(Unicode)** : 16비트 → 21비트 확장, **전 세계 모든 문자** 지원

### 3) 유니코드 변환 형식 8비트 : **UTF-8과 유니코드 인코딩 방식 정리**

#### **1. 왜 8비트를 사용할까?**

* 컴퓨터는 기본적으로 **8비트(1바이트) 단위**로 데이터를 처리함.
* **아스키(ASCII)** 문자는 원래 **7비트로 설계**되었지만, **컴퓨터가 8비트를 기본 단위로 사용**하므로 **1바이트(8비트)로 저장**됨.
* 8비트만 사용하면 대부분의 **영어 문자(ASCII)는 표현 가능**하지만, **한글, 중국어, 일본어 등은 표현 불가능**.
* 이를 해결하기 위해 유니코드(Unicode)와 다양한 인코딩 방식(UTF-8, UTF-16, UTF-32)가 등장.

#### **2. 유니코드와 인코딩(Encoding)**

{% hint style="success" %}
우리는 `비트` 같은 추상화를 사용해 `숫자`를 표현하고, 숫자를 사용해 `문자`를 표현하고, 다시 다른 숫자를 사용해 이런 `숫자`를 표현한다.
{% endhint %}

* **유니코드 (Unicode)**: 전 세계 모든 문자를 고유한 숫자 코드(코드 포인트)로 표현하는 표준
* 하지만, **유니코드 자체는 단순한 숫자 코드일 뿐** → 컴퓨터에서 사용하려면 **인코딩(Encoding) 방식**이 필요함.
* `인코딩(Encoding)`이란?
  * 특정 비트 패턴을 사용하여 유니코드 문자(코드 포인트)를 저장하는 방법.

💡 **대표적인 인코딩 방식**

1. **UTF-8 (Unicode Transformation Format - 8 bit)**
   * 가장 널리 쓰이는 인코딩 방식.
   * **아스키(ASCII)와 완벽한 하위 호환**을 제공 뿐만 아니라 효울성이 좋음
   * 문자마다 `다른 크기의 바이트(1~4바이트)`를 사용하여 저장
     * 아스키가 아닌 문자의 경우 아스키를 받아서 처리하는 프로그램이 깨지지 않는 방법으로 문자 인코등
2. **UTF-16**
   * **16비트(2바이트) 단위**로 문자를 저장.
   * 아스키 문자도 16비트로 표현 → 비효율적일 수 있음.
   * 일부 문자는 4바이트(2개의 16비트 블록)를 사용함.
3. **UTF-32**
   * **모든 문자를 32비트(4바이트)로 표현**.
   * 고정된 크기이므로 단순하지만, **메모리 사용량이 많음**.

#### **3. UTF-8 인코딩 방식**

UTF-8은 **문자의 코드 포인트 크기에 따라 가변 길이(1\~4바이트)를 사용**함.

| **유니코드 범위**          | **UTF-8 바이트 수** | **비트 수** | **예시 문자**    |
| -------------------- | --------------- | -------- | ------------ |
| `U+0000 ~ U+007F`    | 1바이트            | 7비트      | A (U+0041)   |
| `U+0080 ~ U+07FF`    | 2바이트            | 11비트     | π (U+03C0)   |
| `U+0800 ~ U+FFFF`    | 3바이트            | 16비트     | ♣ (U+2663)   |
| `U+10000 ~ U+10FFFF` | 4바이트            | 21비트     | 🐱 (U+1F431) |

💡 **UTF-8의 특징**

* **영어(ASCII) 문자는 1바이트**(8비트)로 저장 → 기존 아스키(ASCII)와 호환됨.
* 유럽어, 그리스어, 아랍어 등은 **2바이트**.
* 한글, 중국어, 일본어 문자 등은 **3바이트**.
* 이모지 같은 확장 문자는 **4바이트**.

#### **4. UTF-8 인코딩 방식 예제**

#### ✅ **A (U+0041)의 경우**

* `A`는 **ASCII에 포함** → **UTF-8로 인코딩 시 1바이트 사용**.
* **유니코드 코드 포인트:** `U+0041`
* **이진수 표현:** `00000000 01000001`
* **UTF-8 인코딩 결과:** `0x41`

✅ **π (U+03C0)의 경우**

* **유니코드 코드 포인트:** `U+03C0`
* **이진수 표현:** `00000011 11000000`
* **UTF-8 인코딩:**
  * 2바이트로 표현해야 함 → 첫 바이트는 `110xxxxx`, 두 번째 바이트는 `10xxxxxx`
  * 결과: `11001111 10000000` (`0xCF 0x80`)

✅ **♣ (U+2663)의 경우**

* **유니코드 코드 포인트:** `U+2663`
* **이진수 표현:** `00100110 01100011`
* **UTF-8 인코딩:**
  * 3바이트로 표현해야 함 → 첫 바이트는 `1110xxxx`, 두 번째/세 번째 바이트는 `10xxxxxx`
  * 결과: `11100010 10011001 10100011` (`0xE2 0x99 0xA3`)

✅ **🐱 (U+1F431)의 경우**

* **유니코드 코드 포인트:** `U+1F431`
* **이진수 표현:** `00011111 01000011 00010001`
* **UTF-8 인코딩:**
  * 4바이트로 표현해야 함 → 첫 바이트는 `11110xxx`, 이후는 `10xxxxxx`
  * 결과: `11110000 10011111 10010000 10110001` (`0xF0 0x9F 0x90 0xB1`)

#### **5. UTF-8의 장점**

✅ **아스키(ASCII)와 100% 호환됨** → 영어 사용자는 추가 메모리 소모 없이 기존 방식 유지.\
✅ **가변 길이 인코딩** → 공간을 효율적으로 사용 가능.\
✅ **모든 유니코드 문자 표현 가능** → 한글, 일본어, 중국어, 이모지 모두 표현 가능.\
✅ **널리 사용됨** → 거의 모든 운영체제(OS)와 웹 브라우저가 기본적으로 UTF-8을 지원.

#### **🎯 최종 정리**

* 컴퓨터가 기본적으로 8비트를 사용하기 때문에 아스키(ASCII)는 8비트로 저장.
* 아스키(ASCII) 문자만 사용할 경우, UTF-8은 동일한 8비트를 사용하여 공간 낭비가 없음.
* UTF-8은 문자에 따라 1\~4바이트를 사용하여 전 세계 모든 문자를 효율적으로 표현.
* **첫 바이트의 비트 패턴을 통해 문자 경계를 쉽게 구분할 수 있음.**
* 이모지(🐱)와 같은 **확장 문자는 4바이트**로 표현됨.

{% hint style="danger" %}
여기서 잠깐 : 왜 일부 문자는 1바이트(8비트), 다른 문자는 4바이트(32비트)인가? 분명 한 문 자를 8비트로 표현한다고 했는데?
{% endhint %}

1. **기본 개념: 바이트와 비트**

* **1바이트(Byte) = 8비트(Bit)**
* **2바이트 = 16비트**
* **3바이트 = 24비트**
* **4바이트 = 32비트**

💡 **즉, "4바이트"라고 하면 32비트(4 × 8)라는 뜻!**\
**하지만, 4바이트로 표현된다고 해서 기본적으로 16비트를 의미하는 것은 아님.**

2. **문자(유니코드)는 크기가 다르다!**

컴퓨터에서 문자를 저장하는 방식은 유니코드(Unicode) + 인코딩(UTF-8, UTF-16, UTF-32)에 따라 달라짐.

* **영어 알파벳 (A, B, C 등) → 1바이트(8비트)**
* **유럽어, 아랍어, 그리스어 문자 → 2바이트(16비트)**
* **한글, 중국어, 일본어 등 → 3바이트(24비트)**
* **이모지(🐱, 😂, 🚀 등) → 4바이트(32비트)**

✅ **즉, 문자의 종류에 따라 필요한 크기가 다르다!**\
이 때문에 일부 문자는 1바이트(8비트), 일부 문자는 4바이트(32비트)를 사용한다.

3. **UTF-8은 가변 길이 인코딩 방식**

<figure><img src="https://498337729-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqKPDlntOwGZBfzPFGkYi%2Fuploads%2FdKUxvhWJHbrlmKKM8B33%2Fimage.png?alt=media&#x26;token=343af31b-09a7-447a-9aa3-fc915095dcaf" alt=""><figcaption></figcaption></figure>

> UTF-8은 **문자마다 필요한 만큼 바이트(1\~4바이트)를 할당**하는 **가변 길이 인코딩**을 사용.

| **유니코드 범위**          | **UTF-8 바이트 수** | **비트 수** | **예시 문자**       |
| -------------------- | --------------- | -------- | --------------- |
| `U+0000 ~ U+007F`    | 1바이트            | 8비트      | A (U+0041)      |
| `U+0080 ~ U+07FF`    | 2바이트            | 16비트     | π (U+03C0)      |
| `U+0800 ~ U+FFFF`    | 3바이트            | 24비트     | 한글 '가' (U+AC00) |
| `U+10000 ~ U+10FFFF` | 4바이트            | 32비트     | 🐱 (U+1F431)    |

> 💡 **즉, UTF-8은 문자의 복잡도에 따라 1\~4바이트를 동적으로 사용하여 저장!**

4. &#x20;**왜 일부 문자는 4바이트(32비트)로 저장될까?**

> **이모지(🐱, 😂, 🚀) 같은 특수 문자는 유니코드 코드 포인트가 크기 때문에 4바이트가 필요함.**

예를 들어 🐱(고양이 이모지)의 유니코드 값:

* **U+1F431** → 16진수로 보면 5자리 숫자
* 8비트(1바이트)로 표현할 수 없음 → **4바이트(32비트) 필요**

💡 **즉, 단순한 문자(영어, 숫자)는 1바이트로 충분하지만, 복잡한 문자는 더 많은 바이트(2\~4바이트)가 필요!**

5. **UTF-8의 장점: 왜 가변 길이 인코딩을 사용할까?**

* **공간 절약**: 영어만 사용하면 1바이트만 사용 → 불필요한 공간 낭비 방지.
* **유연성**: 모든 언어(한글, 중국어, 일본어, 이모지 등)를 저장 가능.
* **아스키(ASCII)와 호환**: 기존 영어 기반 시스템에서도 그대로 사용 가능.

#### **최종 정리**

📌 문자마다 저장 크기가 다름 → 간단한 문자는 1바이트, 복잡한 문자는 4바이트 사용.\
📌 UTF-8은 문자의 복잡도에 따라 1\~4바이트를 동적으로 할당하는 방식.\
📌 영어(A, B, C)는 1바이트(8비트), 한글(가, 나, 다)은 3바이트(24비트), 이모지(🐱, 🚀)는 4바이트(32비트).\
📌 UTF-8은 공간 절약 + 아스키(ASCII)와 호환되는 최적의 인코딩 방식!

### 4) **UTF-8에서 8비트(1바이트)만으로 32비트(4바이트)까지 확장하는 원리**

{% hint style="warning" %}
UTF-8은 **가변 길이 인코딩** 방식을 사용해 **최소 1바이트에서 최대 4바이트까지 동적으로 확장**할 수 있다.
{% endhint %}

1. **UTF-8의 비트 구조**

UTF-8에서 `첫 번째 바이트의 앞쪽 비트(MSB, Most Significant Bit)`를 이용해서 **이 문자가 몇 바이트로 이루어졌는지를 알려줍니다.**

> 즉, **첫 바이트의 앞쪽 비트(접두사) 보고 이 문자가 1\~4바이트 중 몇 바이트를 사용하는지를 알 수 있음!**

| 문자 범위                                         | 코드 포인트 범위            | 바이트 수    | 첫 바이트 패턴                              |
| --------------------------------------------- | -------------------- | -------- | ------------------------------------- |
| <p>아스키 (ASCII),<br>문자(0~178)</p>              | `U+0000 ~ U+007F`    | **1바이트** | `0xxxxxxx`                            |
| <p>기본 라틴 문자 외의 문자(라틴, 아랍ㅇㅓ)<br>: 128~2047</p> | `U+0080 ~ U+07FF`    | **2바이트** | `110xxxxx 10xxxxxx`                   |
| <p>한자, 한글 등<br>: 2048~65535</p>               | `U+0800 ~ U+FFFF`    | **3바이트** | `1110xxxx 10xxxxxx 10xxxxxx`          |
| <p>이모지, 복잡한 문자<br>: 65536~10FFFF</p>          | `U+10000 ~ U+10FFFF` | **4바이트** | `11110xxx 10xxxxxx 10xxxxxx 10xxxxxx` |

&#x20;

**2. 바이트 수를 어떻게 결정하는가?**

UTF-8에서 문자 인코딩을 결정하는 **첫 번째 바이트 패턴**을 보면 다음과 같다.&#x20;

1️⃣ **1바이트 문자 (ASCII, 7비트)**

* 형식: `0xxxxxxx`
* 예: `A` (`U+0041` → `0x41`)
* `A`는 아스키 문자이므로 **1바이트만 사용**

2️⃣ **2바이트 문자 (확장 라틴 문자 등)**

* 형식: `110xxxxx 10xxxxxx`
* 예: `é` (`U+00E9` → `0xC3 0xA9`)
* 첫 바이트가 `110`으로 시작하면 **2바이트 사용**

3️⃣ **3바이트 문자 (한자, 한글, 특수 기호 등)**

* 형식: `1110xxxx 10xxxxxx 10xxxxxx`
* 예: `가` (`U+AC00` → `0xEA 0xB0 0x80`)
* 첫 바이트가 `1110`으로 시작하면 **3바이트 사용**

4️⃣ **4바이트 문자 (이모지, 고유문자 등)**

* 형식: `11110xxx 10xxxxxx 10xxxxxx 10xxxxxx`
* 예: `🐱` (`U+1F431` → `0xF0 0x9F 0x90 0xB1`)
* 첫 바이트가 `11110`으로 시작하면 **4바이트 사용**

**3. 8비트(1바이트)만 있는데 어떻게 4바이트까지 확장 가능할까?**

#### **⭐ 핵심 원리: 다중 바이트를 연결해서 확장**

* 첫 번째 바이트가 몇 바이트를 사용할지를 정해주고,
* 나머지 바이트는 앞쪽에 `10` 비트 패턴을 사용해 연결됨.

> 즉, <mark style="color:red;">각 바이트는 여전히 8비트지만, 여러 개를 합쳐서 32비트까지 확장하는 것</mark>**!**

**🛠️ 예제 분석**

#### **1️⃣ ASCII 문자 ‘A’ (1바이트)**

* **유니코드 코드 포인트:** `U+0041` (10진수 `65`)
* **2진수 표현:** `00000000 01000001` (16비트)
* **UTF-8 인코딩:** `01000001` (1바이트, 아스키와 동일)

➡ **첫 바이트가 `0xxxxxxx`이므로 1바이트만 사용되며, 그대로 저장**

➡ 즉, **A는 아스키 코드 그대로 저장됨** (`0x41`)

***

#### **2️⃣ ‘π’ (그리스 문자, 2바이트)**

* **유니코드 코드 포인트:** `U+03C0` (10진수 `960`)
  * 유니코드 값이 `0x0080~0x07FF` 사이이므로, **2바이트를 사용해야 함**
* **2진수 표현:** `00000011 11000000` (16비트)
* **UTF-8 인코딩:** `11001111 10000000` (2바이트 사용)

```
11001111 10000000  (0xCF 0x80)
```

* 첫 번째 바이트: `110xxxxx` (MSB 3비트를 `110`으로 설정)
* 두 번째 바이트: `10xxxxxx` (MSB 2비트를 `10`으로 설정)
*   실제로 저장되는 데이터:

    ```
    11001111 (첫 번째 바이트, 5비트 데이터 포함)
    10000000 (두 번째 바이트, 6비트 데이터 포함)
    ```
* 이렇게 하면 <mark style="color:red;">11비트(5비트 + 6비트)</mark>를 모두 저장할 수 있음.

***

#### **3️⃣ ‘가’ (한글, 3바이트)**

* **유니코드:** `U+AC00` (10진수 `44032`)
* **2진수 표현:** `10101100 00000000` (16비트)

#### **🔍 UTF-8 인코딩 과정**

`U+AC00`는 **0x0800\~0xFFFF 범위에 속하므로 3바이트 사용**

* 첫 번째 바이트: **1110xxxx** (MSB 4비트를 `1110`으로 설정) ➡ **첫 바이트가 `1110xxxx`이므로 3바이트 사용**
* 두 번째 바이트: **10xxxxxx** (MSB 2비트를 `10`으로 설정)
* 세 번째 바이트: **10xxxxxx** (MSB 2비트를 `10`으로 설정)

#### **✅ 실제 변환 결과**

```scss
11101010 10110000 10000000
(EA B0 80)
```

* **첫 번째 바이트:** `11101010` (4비트 데이터 포함)
* **두 번째 바이트:** `10110000` (6비트 데이터 포함)
* **세 번째 바이트:** `10000000` (6비트 데이터 포함)

➡ **총 16비트(4비트 + 6비트 + 6비트)를 저장**\
➡ **UTF-8에서 한글 1자는 3바이트를 차지함**

***

#### **4️⃣ ‘🐱’ (이모지, 4바이트)**

* **유니코드:** `U+1F431` (10진수 `128049`)
* **2진수 표현:** `00011111 01000011 00010001` (21비트)

#### **🔍 UTF-8 인코딩 과정**

`U+1F431`는 **0x10000\~0x10FFFF 범위에 속하므로 4바이트 사용**

* 첫 번째 바이트: **11110xxx** (MSB 5비트를 `11110`으로 설정) ➡ **첫 바이트가 `11110xxx`이므로 4바이트 사용**
* 두 번째 바이트: **10xxxxxx** (MSB 2비트를 `10`으로 설정)
* 세 번째 바이트: **10xxxxxx** (MSB 2비트를 `10`으로 설정)
* 네 번째 바이트: **10xxxxxx** (MSB 2비트를 `10`으로 설정)

#### **✅ 실제 변환 결과**

```scss
11110000 10011111 10010000 10110001
(F0 9F 90 B1)
```

* **첫 번째 바이트:** `11110000` (3비트 데이터 포함)
* **두 번째 바이트:** `10011111` (6비트 데이터 포함)
* **세 번째 바이트:** `10010000` (6비트 데이터 포함)
* **네 번째 바이트:** `10110001` (6비트 데이터 포함)

➡ **총 21비트(3비트 + 6비트 + 6비트 + 6비트)를 저장**\
➡ **UTF-8에서 이모지는 4바이트를 차지함**



**결론**

* UTF-8은 **첫 번째 바이트의 앞쪽 비트 패턴을 사용해 바이트 수를 결정**
* **모든 문자는 최소 1바이트\~최대 4바이트로 동적 확장 가능**
* **각 바이트는 여전히 8비트지만, 여러 개를 연결하여 32비트까지 표현 가능!**&#x20;

***

### 5) **일상생활 예시: 우체국과 편지 봉투**

UTF-8에서 아스키 문자를 처리하는 방식을 **우체국(ASCII)과 국제 택배(UTF-8)의 차이**로 이해해볼 수 있어요.

📌 **우체국(ASCII)**

* 미국(ASCII)에서 편지를 보낼 때는 그냥 **영어 주소만 적으면 끝!**
* 간단하고 빠름 → 한글, 일본어, 중국어 등 복잡한 언어가 없음.

📌 **국제 택배(UTF-8)**

* 한국에서 외국으로 택배를 보낼 때(유니코드 문자 사용) → **추가적인 스티커(인코딩)가 필요함!**
* 예를 들어, **한글 ‘가’(U+AC00)를 국제 배송하려면 3바이트(UTF-8)로 변환**해야 함.
* 반면, **영어(A\~Z, 숫자 0\~9)는 그냥 그대로 전달 가능!**

> 즉, **영어(아스키)는 그대로 사용 가능하지만, 한글, 중국어, 이모지는 추가적인 포장(UTF-8 인코딩)이 필요!**

## 11.문자를 사용한 수 표현

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

컴퓨터 간 통신에서는 **제어 문자**와 **7비트 환경** 때문에 <mark style="color:red;">8비트 데이터를 직접 주고받기 어려운 문제가 있었다.</mark> (**7비트 환경에서 8비트 데이터를 전송하기 위한 인코딩 기법**)

> 이를 해결하기 위해 **Quoted-Printable (QP) 인코딩**과 **Base64 인코딩**이 등장했다.

#### **1. Quoted-Printable (QP) 인코딩**

* **용도:** 7비트만 지원하는 통신 환경에서도 **8비트 데이터를 송수신**할 수 있도록 하는 인코딩
* **주로 사용된 곳:** **전자우편(Email) 첨부 파일 전송**

#### **2. 인코딩 방식**

* **출력 가능한 ASCII 문자만 사용**
* **8비트 값을 표현**할 &#xB54C;**`=` 뒤에** 바이트의 각 니블을 표현하는 **16진수 2자리로 변환**
* 예: `=` 문자를 그대로 사용할 수 없으므로 `=3D`로 변환
  * 위의 8비트 표현 인해 `=`가 특별한 의미를 지니기 때문인 이유
* 줄 끝의 공백(space)과 탭(tab)도 `=20`, `=09`로 변환해야 함
* 한 줄은 **최대 76자**까지 제한됨

#### **3. 예제**

| 원본 데이터        | QP 인코딩          |
| ------------- | --------------- |
| `hello=world` | `hello=3Dworld` |
| `Tab 공백`      | `Tab=09공백=20`   |

➡ `=` 기호를 이용해 **16진수 값으로 변환**하는 것이 특징

{% hint style="danger" %}
잘 작동은 하나, 1바이트를 표현하기 위해 3바이트를 사용하기 때문에 **아주 비효율적**이다
{% endhint %}

이 뜻은 **QP 인코딩에서 "1바이트를 3바이트로 변환한다"는 말은, 특정 8비트 문자를 `=XX` 형식으로 변환한다는 뜻이다.**

> **QP 인코딩의 핵심 원리**

1. **아스키(ASCII)에서 안전한 문자**는 그대로 유지.
   * 예: `Hello, world!` → 그대로 유지됨.
2. **특수 문자(8비트 문자 또는 공백 등)는 =XX(16진수)로 변환.**
   * 예: 공백(ASCII 32) → `=20`
   * 예: `é`(ASCII 233) → `=E9`
   * 예: `ü`(ASCII 252) → `=FC`
3. **줄 끝에 공백이 있으면 `=XX`로 변환해야 함.**
   * `Hello` → `Hello=20`
   * `Hello.` → `Hello.=20`

> **"1바이트를 표현하기 위해 3바이트를 사용한다"는 의미**

* **특정 문자는 =XX(16진수) 형태로 표현되는데, 이때 원래 1바이트였던 문자가 3바이트로 변함.**
  * 예: `é` (1바이트) → `=E9` (3바이트)
  * 예: 공백(1바이트) → `=20` (3바이트)
  * 예: `ü` (1바이트) → `=FC` (3바이트)

👉 **즉, 원래 1바이트였던 문자가 `=`와 두 개의 16진수(2글자)를 포함하면서 3바이트로 늘어나는 것!**

> **예제 비교**

#### **✅ 원본 텍스트 (아스키 문자만 있는 경우)**

```plaintext
Hello, world!
```

➡ **QP 인코딩 결과 (그대로 유지됨)**

```plaintext
Hello, world!
```

✅ **공백이나 특수 문자가 없어서 원본 크기 유지됨.**

#### **❌ 공백이 포함된 경우**

```plaintext
Hello, world! 
```

➡ **QP 인코딩 결과 (`=20` 추가됨)**

```plaintext
Hello, world!=20
```

🚨 **공백(** **)이 `=20`(3바이트)로 변환됨.**

> **"1바이트가 3바이트로 늘어나는 경우" 정리**

| 문자        | 아스키 값 (10진수) | QP 인코딩 |
| --------- | ------------ | ------ |
| 공백(Space) | 32           | `=20`  |
| é         | 233          | `=E9`  |
| ü         | 252          | `=FC`  |
| á         | 225          | `=E1`  |

📌 **즉, QP 인코딩은 8비트 문자를 7비트 환경에서도 사용할 수 있도록 변환하지만, 비효율적으로 크기가 증가함.**

### 2) **Base64 인코딩**

> 지금보다 컴퓨터 사이의 통신 속도가 훨 씬 느렸던 과거에는 이런 효율성이 정말 중요했다. 그래서 Base64 인코딩이 효율적으로 필요했음

{% hint style="success" %}
Base64 인코딩은 **3바이트 데이터를 4문자**로 표현한다. 3바이트 데이터의 24비트 -> 4가지 6비트 -> 각 덩어리 6비트에 출력 가능한 문자 할당
{% endhint %}

#### **1. Base64 인코딩**

* **용도:** 8비트 바이너리 데이터를 안전하게 **ASCII 문자로 변환**
* **주로 사용된 곳:**
  * 이메일 첨부 파일 전송 (MIME)
  * <mark style="color:purple;">이미지, 동영상 인코딩</mark>
  * JWT(JSON Web Token) 토큰 인코딩
  * URL-safe 데이터 인코딩

#### **2. 인코딩 방식**

<figure><img src="https://498337729-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqKPDlntOwGZBfzPFGkYi%2Fuploads%2FnHGpRqm3GOUygnsWJwtR%2Fimage.png?alt=media&#x26;token=08eb5e67-3cfb-4ca1-aa72-9d8621490dcb" alt=""><figcaption></figcaption></figure>

* 3바이트(24비트) 데이터를 **4개의 6비트 블록**으로 변환
* 각 6비트 블록을 **Base64 문자 테이블**에 매핑
* 매핑된 문자는 **A-Z, a-z, 0-9, `+`, `/`** (총 64개 문자 사용)
* 원본 데이터 길이가 3바이트의 배수가 아닐 경우 **패딩(`=`) 추가**

#### **3. Base64 변환 테이블**

| 숫자 | 문자 | 숫자 | 문자 | 숫자 | 문자 | 숫자 | 문자 |
| -- | -- | -- | -- | -- | -- | -- | -- |
| 0  | A  | 16 | Q  | 32 | g  | 48 | w  |
| 1  | B  | 17 | R  | 33 | h  | 49 | x  |
| 2  | C  | 18 | S  | 34 | i  | 50 | y  |
| 3  | D  | 19 | T  | 35 | j  | 51 | z  |
| 4  | E  | 20 | U  | 36 | k  | 52 | 0  |
| 5  | F  | 21 | V  | 37 | l  | 53 | 1  |
| 6  | G  | 22 | W  | 38 | m  | 54 | 2  |
| 7  | H  | 23 | X  | 39 | n  | 55 | 3  |
| 8  | I  | 24 | Y  | 40 | o  | 56 | 4  |
| 9  | J  | 25 | Z  | 41 | p  | 57 | 5  |
| 10 | K  | 26 | a  | 42 | q  | 58 | 6  |
| 11 | L  | 27 | b  | 43 | r  | 59 | 7  |
| 12 | M  | 28 | c  | 44 | s  | 60 | 8  |
| 13 | N  | 29 | d  | 45 | t  | 61 | 9  |
| 14 | O  | 30 | e  | 46 | u  | 62 | +  |
| 15 | P  | 31 | f  | 47 | v  | 63 | /  |

**🔹 예제: 숫자 `0, 1, 2`의 Base64 변환**

**입력 값 (10진수):**

```
0 1 2
```

**이진수 변환:**

```
00000000 00000001 00000010 (3바이트, 24비트)
```

**6비트씩 나누기:**

```
000000 000000 000001 000010
```

**Base64 문자 매핑:**

```
A A E C
```

➡ **Base64 인코딩 결과: `AAEC`**

***

4. **Base64 패딩 (Padding)**

Base64는 `3바이트(24비트)`씩 데이터를 변환하는데, **원본 데이터가 3바이트의 배수가 아닐 경우** 패딩(`=`)을 사용하여 길이를 맞춘다.

#### **💡 예제**

| 원본 데이터       | Base64 인코딩 |
| ------------ | ---------- |
| `hi` (2바이트)  | `aGk=`     |
| `A` (1바이트)   | `QQ==`     |
| `cat` (3바이트) | `Y2F0`     |

➡ **2바이트 남으면 `=` 추가, 1바이트 남으면 `==` 추가**

### **최종 정리**

| 인코딩 방식         | 용도                  | 특징                     | 예제                            |
| -------------- | ------------------- | ---------------------- | ----------------------------- |
| **QP 인코딩**     | 이메일 전송              | `=` 기호 사용, 16진수 변환     | `hello=3Dworld`               |
| **Base64 인코딩** | 첨부 파일, JWT, URL 인코딩 | 3바이트 → 4문자, 패딩(`=`) 사용 | `c2VjcmV0` (Base64로 "secret") |

* **QP 인코딩**은 **문자 데이터를 손상 없이 송수신할 때 사용**
* **Base64 인코딩**은 **바이너리 데이터를 ASCII로 안전하게 변환할 때 사용** 🚀

### 3) URL 인코딩

1. **URL에서 인코딩이 필요한 이유**

웹에서 `URL(Uniform Resource Locator)`은 리소스를 찾기 위한 주소 역할을 한다.\
하지만 **특정 문자는 URL에서 특별한 의미**를 가지므로, **문자 그대로(literal) 사용하기 어렵다**.

🔹 예를 들어:

* **슬래시(/)** → URL에서 디렉터리 구분자로 사용됨.
* **공백( )** → URL에서 허용되지 않음.
* **& (앰퍼샌드)** → 쿼리 파라미터 구분자로 사용됨.
* **% (퍼센트 기호)** → URL 인코딩에서 특별한 의미를 가짐.

👉 따라서, **특별한 의미가 있는 문자를 문자 그대로(literal) 표현할 방법이 필요하다!**\
👉 이를 위해 **퍼센트 인코딩(Percent-Encoding, URL Encoding)** 방식을 사용한다.



2. **퍼센트 인코딩(Percent-Encoding) 원리**

* **각 문자를 16진수(헥사 코드)로 변환**한 후, **앞에 `%`를 붙이는 방식**으로 인코딩.
* **형식:** `%XX` (XX는 해당 문자의 16진수 값)

🔹 예제:

| 문자        | 아스키 코드(10진수) | 16진수(헥사) | URL 인코딩 |
| --------- | ------------ | -------- | ------- |
| 공백(Space) | 32           | 20       | `%20`   |
| 슬래시(/)    | 47           | 2F       | `%2F`   |
| 퍼센트(%)    | 37           | 25       | `%25`   |
| 앰퍼샌드(&)   | 38           | 26       | `%26`   |
| 등호(=)     | 61           | 3D       | `%3D`   |

3. **퍼센트 인코딩 예제**

🔹 **일반적인 URL**

```plaintext
https://example.com/search?query=hello world
```

{% hint style="danger" %}
**공백(Space)은 허용되지 않음!**
{% endhint %}

🔹 **퍼센트 인코딩된 URL**

```plaintext
https://example.com/search?query=hello%20world
```

✅ **공백( ) → `%20`으로 인코딩되어 문제없이 사용 가능!**

4. **퍼센트 인코딩이 필요한 상황**

&#x20;**(1) URL에 공백이 포함될 때 : 공백은 URL에서 사용할 수 없음!**

```plaintext
https://example.com/my file.html
```

```plaintext
https://example.com/my%20file.html
```

**(2) URL에 `/`(슬래시)를 그대로 사용하고 싶을 때**

```plaintext
https://example.com/api/users/123/edit
```

여기서는 `/`가 디렉터리 구분자로 사용되므로, 특별한 의미가 있음. 하지만 만약 `/`를 **일반 문자로 사용**하고 싶다면?

```plaintext
https://example.com/api%2Fusers%2F123%2Fedit
```

이렇게 하면 `/`가 디렉터리 구분자가 아니라 **일반 문자로 해석됨!**

**(3) URL에 `&`(앰퍼샌드) 포함될 때**

```plaintext
https://example.com/search?query=hello&name=world
```

여기서 `&`는 **파라미터 구분자로** 사용됨. 하지만 `&`를 문자 그대로 표현하고 싶다면?

```plaintext
https://example.com/search?query=hello%26name%3Dworld
```

✅ `%26`로 인코딩하면 `&`를 일반 문자로 인식!

5. **퍼센트 인코딩이 적용되는 곳**

* 웹 브라우저 (주소창 자동 인코딩)
* HTTP 요청 (GET, POST 데이터 전송 시)
* HTML 폼 데이터 전송 (application/x-www-form-urlencoded)
* REST API 요청 시 특수 문자 처리
* QR 코드 URL 인코딩

***

6. **퍼센트 인코딩을 처리하는 코드 예제**

**Python에서 URL 인코딩하는 방법**

```python
import urllib.parse

text = "hello world & special/chars"
encoded_text = urllib.parse.quote(text)

print(encoded_text)  # hello%20world%20%26%20special%2Fchars
```

**JavaScript에서 URL 인코딩하는 방법**

```javascript
const text = "hello world & special/chars";
const encodedText = encodeURIComponent(text);

console.log(encodedText);  // hello%20world%20%26%20special%2Fchars
```

#### **🎯 최종 정리**

* 퍼센트 인코딩(Percent-Encoding, URL Encoding)은 **특수 문자를 URL에서 안전하게 표현**하는 방법이다.
* **형식:** `%XX` (XX는 해당 문자의 16진수 값)
* **공백( )은 `%20`**, **슬래시(/)는 `%2F`**, **퍼센트(%)는 `%25`** 등으로 변환됨.
* &#x20;**웹 브라우저, API 요청, HTML 폼 데이터 전송 등에 사용됨.**
* Python의 `urllib.parse.quote()`나 JavaScript의 `encodeURIComponent()`를 사용하여 자동 변환 가능!&#x20;

## 12. 색을 표현하는 방법

### 1) 투명도 추가

**1️⃣픽셀과 RGB 색 모델**

컴퓨터 그래픽스에서는 `픽셀(Pixel, Picture Element)`을 사용하여 이미지를 표현한다.\
픽셀은 색을 가지며, 컴퓨터 모니터는 **빨간색(R), 녹색(G), 파란색(B)**&#xC744; 조합하여 색을 만든다.

> 이러한 색 표현 방식을 <mark style="color:blue;">RGB 색 모델(RGB Color Model)</mark>이라고 한다.

📌 **RGB 색 모델의 원리**\
![](https://498337729-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqKPDlntOwGZBfzPFGkYi%2Fuploads%2FO9oDhGkbO1K9mYRUhIB1%2Fimage.png?alt=media\&token=b3afec29-3b2e-4c06-931b-86f84cd58e7b)

* **(0,0,0) → 검은색** (모든 빛이 꺼진 상태)
* **(1,1,1) → 흰색** (모든 빛이 최대로 켜진 상태)
* **(1,0,0) → 빨간색**
* **(0,1,0) → 녹색**
* **(0,0,1) → 파란색**
* **(1,1,0) → 노란색** (빨강 + 녹색)
* **(0,1,1) → 청록색(Cyan)** (녹색 + 파랑)
* **(1,0,1) → 자홍색(Magenta)** (빨강 + 파랑)
* **(0.5, 0.5, 0.5) → 회색** (빛의 강도를 낮춤)

이처럼 RGB 모델에서는 빛을 추가하여 색을 표현하는데, 이를 **가산 색 시스템(Additive Color System)**&#xC774;라고 한다.



**2️⃣ 가산 색 시스템 vs 감산 색 시스템**

* **가산 색 시스템(Additive Color System)**
  * RGB 모델처럼 **빛을 섞어 색을 표현**하는 방식.
  * 컴퓨터 모니터, TV, 프로젝터 등에 사용됨.
  * 빛을 더할수록 밝아지고, 모두 더하면 흰색이 됨.
*   **감산 색 시스템(Subtractive Color System)**

    * 청록색(Cyan), 자홍색(Magenta), 노란색(Yellow)을 기본 색으로 사용.
    * **인쇄물, 프린터**에서 사용되며, <mark style="color:red;">흰 배경에서 특정 색을 제거하여 원하는 색</mark>을 표현.
    * 색을 섞을수록 어두워지고, 모두 더하면 검은색이 됨.



**3️⃣ 컴퓨터에서 색 표현 (RGB & 24비트 컬러)**

{% hint style="info" %}
현대 컴퓨터는 **색을 24비트(3바이트)로 표현**한다. 1천만에 가장 가까운 2의 제곱수에 해당하는 색을 표현 할 수 있다.\
각 색(R, G, B)은 8비트(1바이트)씩 할당되어, 총 **2³² ≈ 1677만 개의 색상**을 표현 가능하다.
{% endhint %}

**RGB 24비트 색 표현 방식**

* **빨간색(R)**: 8비트 (0\~255)
* **녹색(G)**: 8비트 (0\~255)
* **파란색(B)**: 8비트 (0\~255)
* 예: **순수 빨강 (255, 0, 0) → 11111111 00000000 00000000 (16진수: 0xFF0000)**

**색 표현 예시**

| 색상 | 10진수 표현 (R,G,B) | 16진수 표현   |
| -- | --------------- | --------- |
| 검정 | (0, 0, 0)       | `#000000` |
| 흰색 | (255, 255, 255) | `#FFFFFF` |
| 빨강 | (255, 0, 0)     | `#FF0000` |
| 녹색 | (0, 255, 0)     | `#00FF00` |
| 파랑 | (0, 0, 255)     | `#0000FF` |

***

**4️⃣ 32비트 컬러와 투명도(알파 채널)**

<figure><img src="https://498337729-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FqKPDlntOwGZBfzPFGkYi%2Fuploads%2FUBJb19Q74FeHDZw9gBsr%2Fimage.png?alt=media&#x26;token=2ac44ae5-a89d-4f36-8c4f-077322c756fa" alt=""><figcaption></figcaption></figure>

* **24비트 컬러**에서는 RGB 값만 사용하지만, 컴퓨터에서는 32비트(4바이트)로 색을 저장하기도 한다.
  * 현대 컴퓨터들이 24비트 단 위로 계산을 수행하도록 설계되지 않았기 때문이다. 그 결과 그림 1-20처럼 **24비트에 가장 가까운 표준 크기인 32비트(워드)에 색을 넣어서** 처리하곤 한다
* 추가된 8비트는 "알파 채널(Alpha Channel)"로 사용되며, **투명도(Opacity)**&#xB97C; 결정함.
  * 미사용인 부분을 사용하기 위한 8비트&#x20;

📌 **32비트 색 표현 방식 (RGBA)**

| 8비트(1바이트) | 8비트(1바이트) | 8비트(1바이트) | 8비트(1바이트) |
| --------- | --------- | --------- | --------- |
| 알파(투명도)   | 빨강 (R)    | 녹색 (G)    | 파랑 (B)    |

예: **반투명 빨강 (128, 255, 0, 0) → 10000000 11111111 00000000 00000000 (16진수: 0x80FF0000)**

✅ **알파(Alpha) 값의 의미**

* **0** → 완전 투명 (보이지 않음)
* **128** → 반투명 (50% 불투명)
* **255** → 완전 불투명 (기본 RGB 색상)

**5️⃣ 인간의 눈과 색상 인식**

컴퓨터가 색을 **수학적으로** 표현하는 반면, 인간의 눈은 **비선형적**으로 색을 인식한다.

* 인간의 눈은 **녹색(G)에 가장 민감**하고, **파란색(B)에는 둔감**하다.
* 따라서 **디지털 영상 기술**에서는 감마 보정(Gamma Correction)을 적용하여, 인간의 눈이 더 자연스럽게 색을 인식하도록 한다.

**6️⃣ 결론**

* 컴퓨터는 RGB 색 모델을 사용하여 색을 표현함.
* RGB 모델은 **가산 색 시스템(빛을 더하는 방식)**&#xC774;며, 프린터는 **감산 색 시스템(색을 빼는 방식)**&#xC744; 사용함.
* 현대 컴퓨터는 <mark style="color:blue;">24비트 컬러(8비트씩 R, G, B)</mark>를 사용하여 1677만 개의 색을 표현 가능.
* 32비트 컬러에서는 알파(투명도) 값을 추가하여 RGBA 포맷으로 저장함.
* 인간의 눈은 선형적으로 색을 인식하지 않으며, 감마 보정이 필요함.&#x20;

### 2) 투명도

1. **전통 애니메이션과 투명도의 필요성**

초기 애니메이션에서는 **각 프레임을 손으로 직접 그림** → 배경을 정확히 재생산하기 어려워 **화면이 흔들리는 문제(jitter)** 발생.

📌 **셀 애니메이션(Cell Animation)의 등장**

* 1915년, 존 브레이(John Bray) & 얼 허드(Earl Hurd)가 셀 애니메이션을 발명.
* 캐릭터를 **투명한 필름(셀룰로이드)** 위에 그려서 **고정된 배경 위에서 움직이는 방식**.
* 배경을 다시 그릴 필요가 없어짐 → 작업량 감소 & 일관된 프레임 유지 가능.

📌 **컴퓨터 애니메이션의 발전**

* 1970\~80년대, **컴퓨터 애니메이션 기술 발전**.
* 하지만 당시 컴퓨터 성능이 부족 → **각각의 요소를 개별적으로 그린 후 합성(composite) 필요**.
* 셀 애니메이션처럼 **투명도를 이용한 이미지 합성 기법** 개발됨.

2. **알파 채널(Alpha Channel)과 투명도**

📌 **알파 채널의 개념**

* 1984년, 톰 더프(Tom Duff) & 토머스 포터(Thomas Porter)가 컴퓨터 그래픽에서 **투명도를 수학적으로 정의**.
* 각 픽셀에 **알파(α) 값**을 추가하여 투명도를 결정.
  * **α = 0** → 완전 투명
  * **α = 1 (255)** → 완전 불투명
  * **0 < α < 1** → 반투명 (예: 50% 투명 = α 127)

📌 **알파 블렌딩(Alpha Blending)**

* **색상(RGB) 값에 알파(α)를 곱하여 저장**.
* 예제:
  * 빨강(R) = 200, 녹색(G) = 0, 파랑(B) = 0
  * α = 1.0 (완전 불투명) → 저장된 값: (200, 0, 0, 255)
  * α = 0.5 (50% 투명) → 저장된 값: (100, 0, 0, 127)
* 미리 **RGB 값에 α를 곱해 저장**하면, 픽셀을 사용할 때마다 추가적인 연산이 필요하지 않음.

📌 **RGBA(32비트) 색 표현**

| 비트 위치  | 31-24 | 23-16 | 15-8  | 7-0   |
| ------ | ----- | ----- | ----- | ----- |
| **채널** | 알파(α) | 빨강(R) | 녹색(G) | 파랑(B) |

3. **색상 표현 방식 (웹과 그래픽)**

#### **✅ 웹에서 색상 표현 (Hex 코드)**

웹에서는 색을 16진수(Hex)로 표현하는 **Hex Triplet 방식** 사용.

📌 **색상 표현 형식**

* `#RRGGBB` → R, G, B는 각각 16진수(00\~FF)
* 예제:
  * `#FF0000` → 빨강
  * `#00FF00` → 초록
  * `#0000FF` → 파랑
  * `#FFFF00` → 노랑 (빨강+초록)
  * `#FFFFFF` → 흰색
  * `#000000` → 검정

📌 **알파 채널이 포함된 색상 (RGBA)** 웹에서는 알파 값을 별도로 추가할 수 있음.

* `rgba(255, 0, 0, 0.5)` → 반투명 빨강 (50%)
* CSS에서는 `opacity: 0.5;` 같은 속성을 활용.

### 3) 색 인코딩

{% hint style="warning" %}
웹 페이지는 주로 **UTF-8 문자**로 구성된 **텍스트 기반의 문서**이기 때문에,\
웹에서 색을 사용하려면 **텍스트로 색을 표현하는 방법**이 필요하다.
{% endhint %}

#### **Hex Triplet (16진수 트리플렛)**

웹에서는 **16진수(Hexadecimal) 코드**를 사용해 색을 표현하는 방식이 표준.

📌 **Hex 색상 코드 형식**

```
#RRGGBB
```

* `RR`: **빨간색(R)** (Red, 00\~FF)
* `GG`: **녹색(G)** (Green, 00\~FF)
* `BB`: **파란색(B)** (Blue, 00\~FF)

📌 **예제**

| 색상 | 16진수(Hex) | 의미                    |
| -- | --------- | --------------------- |
| 검정 | `#000000` | (R=0, G=0, B=0)       |
| 흰색 | `#FFFFFF` | (R=255, G=255, B=255) |
| 빨강 | `#FF0000` | (R=255, G=0, B=0)     |
| 초록 | `#00FF00` | (R=0, G=255, B=0)     |
| 파랑 | `#0000FF` | (R=0, G=0, B=255)     |
| 노랑 | `#FFFF00` | (R=255, G=255, B=0)   |
| 회색 | `#808080` | (R=128, G=128, B=128) |

📌 **설명**

* `#FF0000` → 빨강 (Red 255, Green 0, Blue 0)
* `#00FF00` → 초록 (Red 0, Green 255, Blue 0)
* `#0000FF` → 파랑 (Red 0, Green 0, Blue 255)
* `#FFFF00` → 노랑 (빨강+초록)
* `#000000` → 검정 (모든 값이 0)
* `#FFFFFF` → 흰색 (모든 값이 최대)



**투명도(α)와 RGBA 표현**

Hex 코드에는 **투명도(α, 알파 채널)** 정보가 없음.\
웹에서는 **RGBA 형식**을 사용해 투명도를 포함할 수 있음.

📌 **RGBA 색상 코드 형식**

```
rgba(R, G, B, A)
```

* `R`: 빨강 (0\~255)
* `G`: 녹색 (0\~255)
* `B`: 파랑 (0\~255)
* `A`: **알파(투명도)** (0.0 \~ 1.0)
  * 0.0 → 완전 투명
  * 1.0 → 완전 불투명

📌 **예제**

```css
color: rgba(255, 0, 0, 0.5);  /* 반투명 빨강 */
color: rgba(0, 0, 255, 1.0);  /* 완전 불투명 파랑 */
background-color: rgba(0, 255, 0, 0.2);  /* 연한 초록색 배경 */
```

#### **Hex 코드 vs RGBA 비교**

| 표현 방식       | 예제                       | 특징                   |
| ----------- | ------------------------ | -------------------- |
| **Hex 코드**  | `#FF5733`                | 6자리 16진수 (투명도 없음)    |
| **RGBA 코드** | `rgba(255, 87, 51, 0.8)` | 10진수 RGB + 투명도(0\~1) |

✅ 웹에서 색상은 Hex 코드 (`#RRGGBB`)로 표현하며, 16진수로 색을 지정할 수 있음.\
✅ 투명도(α)가 필요할 경우 RGBA(`rgba(R,G,B,A)`) 형식을 사용해야 함.\
✅ Hex 코드만으로는 투명도를 설정할 수 없기 때문에 CSS에서는 `opacity` 또는 `rgba()`를 활용함.&#x20;



## 정리

2장에서는 컴퓨터를 이루는 물리적 구성요소를 이해하고 **왜 컴퓨터가 애초부터 비트를 사용 하는지 이해할 때 도움이 될 수 있도록 하드웨어의 기본**을 배운다
