<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>PiLove</title>
    <link>https://pi-love0314.tistory.com/</link>
    <description>PiLove의 학습일지</description>
    <language>ko</language>
    <pubDate>Tue, 2 Jun 2026 21:51:50 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>PiLove</managingEditor>
    <image>
      <title>PiLove</title>
      <url>https://tistory1.daumcdn.net/tistory/6342917/attach/0d3245f432ce4569b9792a425394ba95</url>
      <link>https://pi-love0314.tistory.com</link>
    </image>
    <item>
      <title>[영상처리] Compression</title>
      <link>https://pi-love0314.tistory.com/entry/%EC%98%81%EC%83%81%EC%B2%98%EB%A6%AC-Compression</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이미지는 기본적으로 용량이 크다. 예를 들어, 흑백 이미지가 1024 x 1024이고, 픽셀당 8 bit이라면, 1024 x 1024 x 8bits 정도의 데이터가 필요하다. 컬러 이미지라면 RGB 3채널이므로 3배의 크기가 필요하다. 그래서 이미지를 저장하거나 전송할 때 압축이 필요하다. 압축에는 두 가지의 종류가 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;무손실 압축(Lossless compression) : Huffman, Run-length&lt;/li&gt;
&lt;li&gt;손실 압축(Lossy compression) : JPEG&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;무손실 압축과 손실 압축의 차이는 말 그대로 압축하는 과정에서 정보의 손실이 있느냐 없느냐로 구분할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Lossless compression&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Huffman coding&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Huffman coding의 핵심은 간단하다. 자주 나오는 값에는 짧은 비트열을 주고, 드물게 나오는 값에는 긴 비트열을 준다. 예를 들어, 어떤 이미지에서 gray value가 다음 확률로 나온다고 가정하자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;545&quot; data-origin-height=&quot;179&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/x8CQD/dJMcaaZGeYN/hzWvlR8X11EIrd5c0piphK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/x8CQD/dJMcaaZGeYN/hzWvlR8X11EIrd5c0piphK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/x8CQD/dJMcaaZGeYN/hzWvlR8X11EIrd5c0piphK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fx8CQD%2FdJMcaaZGeYN%2FhzWvlR8X11EIrd5c0piphK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;545&quot; height=&quot;179&quot; data-origin-width=&quot;545&quot; data-origin-height=&quot;179&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Fixed code라면 값이 4개니까 각각 2bit가 필요하다. 반면, Variable code를 사용한다면, 자주 나올 확률이 높은 gray value에 대하여 짧은 비트열인 1을 할당함으로써 평균 bit 수를 줄일 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 bit 수를 줄임으로써 얼마나 압축이 가능할까? 이를 확인하기 위해 Entropy 라는 개념이 나온다. Entropy는 쉽게 말해 무손실로 압축할 때 이론적으로 필요한 최소 평균 bit 수를 의미한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;643&quot; data-origin-height=&quot;150&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GS1UF/dJMcacQIObH/6LTW9LkFAH2AmgbYVV6Br0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GS1UF/dJMcacQIObH/6LTW9LkFAH2AmgbYVV6Br0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GS1UF/dJMcacQIObH/6LTW9LkFAH2AmgbYVV6Br0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGS1UF%2FdJMcacQIObH%2F6LTW9LkFAH2AmgbYVV6Br0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;643&quot; height=&quot;150&quot; data-origin-width=&quot;643&quot; data-origin-height=&quot;150&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 p_i는 값 gray value가 등장할 확률을 의미한다. 각 gray value의 확률이 0.2, 0.4, 0.3, 0.1이라고 가정했을 때, Entropy는 다음과 같이 계산된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1122&quot; data-origin-height=&quot;69&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c6Cicx/dJMcaaZGlBj/9mtjZTZhzkVuguCwqw9m2k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c6Cicx/dJMcaaZGlBj/9mtjZTZhzkVuguCwqw9m2k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c6Cicx/dJMcaaZGlBj/9mtjZTZhzkVuguCwqw9m2k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc6Cicx%2FdJMcaaZGlBj%2F9mtjZTZhzkVuguCwqw9m2k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1122&quot; height=&quot;69&quot; data-origin-width=&quot;1122&quot; data-origin-height=&quot;69&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 아무리 압축을 잘해도 평균적으로 약 1.8464 bit/pixel 보다 더 낮추기는 어렵다는 의미이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 huffman coding은 어떻게 진행되는가 알아보자. 우선 무작정 자주 나오는 값에 짧은 코드를 아무렇게나 주면 안된다. 왜냐하면 복원이 안될 수 있기 때문이다. A라는 값에 대해 코드 1을 주고 B라는 값에 대해 코드 10을 주고, C라는 값에 대해 코드 11을 주었다고 가정하자. 이 경우 압축된 비트열이 11이면 이 코드가 C인지 AA인지 알아보기 어렵다. 따라서 짧은 code를 주되, 복원할 때 헷갈리지 않은 code 체계를 만들어야 한다. 그래서 필요한 조건이 prefix-free code이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Prefix-free code란, 어떤 code도 다른 code의 앞부분이 되지 않는 코드 체계를 의미한다. 그럼 짧은 code와 긴 code를 적절히 배치하면서, 동시에 복원 가능한 prefix-free code를 어떻게 만들까? 이에 대한 답이 바로 Huffman tree이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Huffman tree는 다음 두 가지를 동시에 만족시키기 위해 등장한다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;자주 나오는 값은 짧은 code를 갖게 한다.&lt;/li&gt;
&lt;li&gt;전체 code가 prefix-free가 되도록 만든다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Huffman tree를 만드는 과정은 다음과 같다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;이미지의 각 gray value 확률을 구한다.&lt;/li&gt;
&lt;li&gt;확률이 가장 작은 두 개를 묶는다.&lt;/li&gt;
&lt;li&gt;묶은 값을 다시 하나의 노드로 보고 또 가장 작은 두 개를 묶는다.&lt;/li&gt;
&lt;li&gt;전체 확률이 1이 될 때까지 위 과정(3)을 반복한다.&lt;/li&gt;
&lt;li&gt;트리의 가지에 0과 1을 붙인다.&lt;/li&gt;
&lt;li&gt;root에서 leaf까지 내려가며 codeword를 읽는다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1070&quot; data-origin-height=&quot;383&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/emT6i0/dJMcaf0X6sT/JGQqxIHJIVnA0zipD5RGvK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/emT6i0/dJMcaf0X6sT/JGQqxIHJIVnA0zipD5RGvK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/emT6i0/dJMcaf0X6sT/JGQqxIHJIVnA0zipD5RGvK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FemT6i0%2FdJMcaf0X6sT%2FJGQqxIHJIVnA0zipD5RGvK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1070&quot; height=&quot;383&quot; data-origin-width=&quot;1070&quot; data-origin-height=&quot;383&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Run-length Encoding, RLE&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Run-length Encoding은 같은 값이 연속되는 구간을 반복 횟수로 표현한다. 예를 들어, 0000011111000 이 있으면, 이는 &quot;5,5,3&quot; 처럼 표현할 수 있다. 이 방식은 특히 값이 0과 1뿐인 binary image에서 좋다. 그러나 일반적인 이미지에서는 사용하기 어렵다. 예시로, 128 129 130 128 131 128 130 ... 이런식으로 사람 눈으로 구분하기 어려운 픽셀값에 대해서 RLE로 표현하면 &quot;(128, 1), (129, 1), (130, 1), (128, 1), (131, 1), (128, 1), (130, 1)&quot; 이런 식으로 오히려 데이터가 더 커질 수 있기 때문이다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Lossy compression&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;JPEG&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;무손실 압축으로는 충분히 줄이기 어렵다. 따라서 손실 압축을 사용하게 되는데, 손실 압축의 배경은 다음과 같다. 우선 사람의 눈은 모든 정보를 똑같이 민감하게 보지 않는다. 예를 들어 전체적인 밝기 변화나 큰 구조는 잘 느끼지만, 아주 미세한 고주파 질감 변화에는 상대적으로 둔감하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;고주파 얘기가 나와서 주파수 영역에 대해 간단하게 소개하자면, 이미지를 바라보는 관점이 공간 영역에서 픽셀값의 변화량의 영역으로 바꾼 것이다. 즉, 이미지를 바라볼 때 픽셀값으로 이미지를 바라보는 것이 아닌 인접한 픽셀값들 사이의 차이, 즉 변화량으로 이미지를 바라보는 것이며, &quot;미세한 고주파 질감 변화&quot; 는 인접한 두 픽셀 사이의 변화량이 큰 픽셀의 관계를 말한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아무튼 다시 본론으로 돌아와서 사람이 잘 못 느끼는 세부 정보는 줄이고, 중요한 구조는 보존하면 용량을 훨씬 줄일 수 있지 않을까? 가 손실 압축인 JPEG의 출발점이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 어떤 정보가 중요하고 덜 중요한지 어떻게 알 수 있을까?&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미지는 픽셀 값으로 저장되어 있다. 픽셀 값 그대로 보면 어떤 값이 중요한지 판단하기 어렵다. 따라서 이미지를 바라보는 관점을 주파수 영역으로 바꾼다. 이때 사용하는 변환이 바로 DCT이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DCT로 변환한 이후에는 Quantization을 해준다. 압축 과정을 대략적으로 표현하면 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;890&quot; data-origin-height=&quot;234&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/crVHqE/dJMcagexZUm/5IKjWLPQOWrdrm3QoVBJ30/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/crVHqE/dJMcagexZUm/5IKjWLPQOWrdrm3QoVBJ30/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/crVHqE/dJMcagexZUm/5IKjWLPQOWrdrm3QoVBJ30/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcrVHqE%2FdJMcagexZUm%2F5IKjWLPQOWrdrm3QoVBJ30%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;890&quot; height=&quot;234&quot; data-origin-width=&quot;890&quot; data-origin-height=&quot;234&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;이미지를 작은 block으로 나눈다.&lt;/li&gt;
&lt;li&gt;각 block에 DCT를 적용한다.&lt;/li&gt;
&lt;li&gt;Quantization을 한다.&lt;/li&gt;
&lt;li&gt;Zigzag scanning을 한다.&lt;/li&gt;
&lt;li&gt;Entropy coding을 한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;복원 과정은 다음과 같다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Entropy decoding&lt;/li&gt;
&lt;li&gt;Inverse quantization&lt;/li&gt;
&lt;li&gt;Inverse DCT&lt;/li&gt;
&lt;li&gt;Block들을 다시 합침&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;DCT&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DCT는 이미지를 여러 주파수 서분으로 나누는 역할을 한다. 쉽게 말하면 8x8 block 하나를 다음과 같은 성분들의 조합으로 표현하는 것이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;전체적으로 밝은 정도&lt;/li&gt;
&lt;li&gt;천천히 변하는 성분&lt;/li&gt;
&lt;li&gt;빠르게 변하는 성분&lt;/li&gt;
&lt;li&gt;세밀한 경계나 질감&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같은 성분들의 조합으로 표현된다. 수식은 다음과 같다. 참고로, DCT는 이미지 block을 여러 cosine basis 패턴의 조합으로 표현하는 변환이다. JPEG에서는 0~255 범위의 픽셀값을 그대로 DCT에 넣기보다, 각 값에서 128을 빼서 -128~127 정도의 0 중심 데이터로 이동시킨 뒤 DCT를 적용한다. 이렇게 하면 block의 평균 밝기 성분이 한쪽으로 크게 치우치는 것을 줄이고, 밝기 변화 성분을 더 다루기 좋은 형태로 변환할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;945&quot; data-origin-height=&quot;236&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bsBQ3H/dJMcaaL8ID8/sZy7PfJjzUPEfiZOty7XGK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bsBQ3H/dJMcaaL8ID8/sZy7PfJjzUPEfiZOty7XGK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bsBQ3H/dJMcaaL8ID8/sZy7PfJjzUPEfiZOty7XGK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbsBQ3H%2FdJMcaaL8ID8%2FsZy7PfJjzUPEfiZOty7XGK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;945&quot; height=&quot;236&quot; data-origin-width=&quot;945&quot; data-origin-height=&quot;236&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;4x4 block을 주파수 영역으로 변환했다고 하자. 각 자리는 다음과 같이 해석할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;455&quot; data-origin-height=&quot;205&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1yxSE/dJMcahxLzSw/fpxxrLkBRyKN10leyUeNE1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1yxSE/dJMcahxLzSw/fpxxrLkBRyKN10leyUeNE1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1yxSE/dJMcahxLzSw/fpxxrLkBRyKN10leyUeNE1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1yxSE%2FdJMcahxLzSw%2FfpxxrLkBRyKN10leyUeNE1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;455&quot; height=&quot;205&quot; data-origin-width=&quot;455&quot; data-origin-height=&quot;205&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;F(0, 0) : 전체 평균 밝기 성분&lt;/li&gt;
&lt;li&gt;F(1, 0) : x방향으로 천천히 변하는 성분&lt;/li&gt;
&lt;li&gt;F(0, 1) : y방향으로 천천히 변하는 성분&lt;/li&gt;
&lt;li&gt;F(3, 3) : x, y 방향으로 빠르게 변하는 고주파 성분&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적으로 DCT의 결과에서 왼쪽 위는 저주파 성분, 오른쪽 아래는 고주파 성분으로 해석한다. 즉, F(0, 0) 근처는 이미지의 큰 구조를 담고 F(3, 3) 근처는 세밀한 변화나 질감을 담는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DCT만 한다고 압축이 되는 것은 아니다. 실제로 용량을 줄이는 과정은 Quantization을 진행해야 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;262&quot; data-origin-height=&quot;353&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SutVV/dJMcaf0YA0T/YzMvmThsuV9qApoYBxfAi0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SutVV/dJMcaf0YA0T/YzMvmThsuV9qApoYBxfAi0/img.png&quot; data-alt=&quot;8x8 block에 대해 각 pixel값 - 128&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SutVV/dJMcaf0YA0T/YzMvmThsuV9qApoYBxfAi0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSutVV%2FdJMcaf0YA0T%2FYzMvmThsuV9qApoYBxfAi0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;262&quot; height=&quot;353&quot; data-origin-width=&quot;262&quot; data-origin-height=&quot;353&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;8x8 block에 대해 각 pixel값 - 128&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;265&quot; data-origin-height=&quot;353&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kVcSi/dJMcacDfxuP/EbLNKHlfdAcyteNjHDOtmK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kVcSi/dJMcacDfxuP/EbLNKHlfdAcyteNjHDOtmK/img.png&quot; data-alt=&quot;DCT 변환&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kVcSi/dJMcacDfxuP/EbLNKHlfdAcyteNjHDOtmK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkVcSi%2FdJMcacDfxuP%2FEbLNKHlfdAcyteNjHDOtmK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;265&quot; height=&quot;353&quot; data-origin-width=&quot;265&quot; data-origin-height=&quot;353&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;DCT 변환&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Quantization&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DCT의 결과를 해석하면 다음과 같다. 사람의 눈이 민감하게 반응하는 정보는 왼쪽 위에 저주파 성분으로 몰려 있고, 덜 민감하게 인식하는 정보는 오른쪽 아래인 고주파 성분으로 몰려있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 오른쪽 아래인 고주파 성분을 대충 저장하거나 0으로 만들면 되지 않을까? 라는 생각에서 출발한 것이 바로 Quantization이다. 각 자리에 대응하는 matrix로 나누고 반올림을 해준다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;148&quot; data-origin-height=&quot;152&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bkNBsf/dJMcab5nbSK/K0p9d2K9cyKdiSmYy97Bv0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bkNBsf/dJMcab5nbSK/K0p9d2K9cyKdiSmYy97Bv0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bkNBsf/dJMcab5nbSK/K0p9d2K9cyKdiSmYy97Bv0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbkNBsf%2FdJMcab5nbSK%2FK0p9d2K9cyKdiSmYy97Bv0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;148&quot; height=&quot;152&quot; data-origin-width=&quot;148&quot; data-origin-height=&quot;152&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왼쪽 위 저주파 영역은 값을 비교적 많이 반영해야하므로 작은 값으로 나누고 반올림을 해주는 반면, 오른쪽 아래 고주파 영역은 0이 되도 상관없기 때문에 큰 값으로 나누고 반올림을 해준다. 결과는 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;272&quot; data-origin-height=&quot;362&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bVi0vq/dJMcagZSAd2/wOZI9AaXI6RAdbOdRWk0Vk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bVi0vq/dJMcagZSAd2/wOZI9AaXI6RAdbOdRWk0Vk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bVi0vq/dJMcagZSAd2/wOZI9AaXI6RAdbOdRWk0Vk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbVi0vq%2FdJMcagZSAd2%2FwOZI9AaXI6RAdbOdRWk0Vk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;272&quot; height=&quot;362&quot; data-origin-width=&quot;272&quot; data-origin-height=&quot;362&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런식으로 Quantization을 진행하면 된다. 그렇다면 손실은 어디서 발생할까? 바로 올림을 하는 부분에서 발생한다. (0, 0) 위치의 -415에 대해서 16으로 나눈 후 반올림을 한 결과가 -26이다. 이 -26을 다시 16으로 곱하여 복원을 하면 -416이 된다. 처음 -415와 1이 차이가 나게 된다. 정리하자면 Quantization에서 나누고 반올림하면서 원래 DCT coefficient의 정확한 값이 사라지는 현상이 발생하여 손실이 생기는 것이다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Zigzag scanning&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;277&quot; data-origin-height=&quot;207&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/baUpvy/dJMcahxLVsc/5MCm9vjLyxzCdjnzgHuFT1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/baUpvy/dJMcahxLVsc/5MCm9vjLyxzCdjnzgHuFT1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/baUpvy/dJMcahxLVsc/5MCm9vjLyxzCdjnzgHuFT1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbaUpvy%2FdJMcahxLVsc%2F5MCm9vjLyxzCdjnzgHuFT1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;277&quot; height=&quot;207&quot; data-origin-width=&quot;277&quot; data-origin-height=&quot;207&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Quantization 이후에는 값을 지그재그로 읽어준다. EOB는 End Of Block이라는 의미로, 이 뒤는 모두 0이 되기 때문에 더 이상 저장하지 않겠다는 의미이다.&amp;nbsp;&lt;/p&gt;</description>
      <category>CS/영상처리</category>
      <author>PiLove</author>
      <guid isPermaLink="true">https://pi-love0314.tistory.com/60</guid>
      <comments>https://pi-love0314.tistory.com/entry/%EC%98%81%EC%83%81%EC%B2%98%EB%A6%AC-Compression#entry60comment</comments>
      <pubDate>Fri, 22 May 2026 21:46:18 +0900</pubDate>
    </item>
    <item>
      <title>[영상처리] Image Restoration</title>
      <link>https://pi-love0314.tistory.com/entry/%EC%98%81%EC%83%81%EC%B2%98%EB%A6%AC-Image-Restoration</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;고영준 교수님 영상처리 강의 내용 정리입니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Image Restoration&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Image Restoration이란, 말 그대로 손상된 이미지를 더 원래 이미지에 가깝게 만드는 작업을 말한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;377&quot; data-origin-height=&quot;48&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bFCT3I/dJMcac394ru/VmJokQ1jv7KBnTXMj6exJ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bFCT3I/dJMcac394ru/VmJokQ1jv7KBnTXMj6exJ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bFCT3I/dJMcac394ru/VmJokQ1jv7KBnTXMj6exJ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbFCT3I%2FdJMcac394ru%2FVmJokQ1jv7KBnTXMj6exJ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;377&quot; height=&quot;48&quot; data-origin-width=&quot;377&quot; data-origin-height=&quot;48&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;638&quot; data-start=&quot;604&quot;&gt;&lt;span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;f&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;: 우리가 얻고 싶은 원래 이미지&lt;/li&gt;
&lt;li data-end=&quot;672&quot; data-start=&quot;639&quot;&gt;&lt;span&gt;&lt;span&gt;g(x,y)&lt;/span&gt;&lt;/span&gt;: 실제로 관측된 손상된 이미지&lt;/li&gt;
&lt;li data-end=&quot;709&quot; data-start=&quot;673&quot;&gt;&lt;span&gt;&lt;span&gt;h(x,y):&lt;/span&gt;&lt;/span&gt;&amp;nbsp;blur를 만드는 필터 또는 커널&lt;/li&gt;
&lt;li data-end=&quot;742&quot; data-start=&quot;710&quot;&gt;&lt;span&gt;&lt;span&gt;n(x,y)&lt;/span&gt;&lt;/span&gt;: 이미지에 추가된 noise&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 실제로 보는 이미지는 원래 이미지에 어떤 blur filter를 거치고 거기에 noise가 더해진 결과라는 가정에서 출발한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Noise는 외부 방해나 센서 문제 등으로 인해 이미지에 생기는 원하지 않는 변화를 말한다. Salt and Pepper noise, Gaussian noise, Speckle noise, Periodic noise, ... 등 다양한 noise가 존재하는데, 이러한 noise의 종류에 따라 적절한 제거 방법이 다르다.&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Salt and Pepper Noise&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;426&quot; data-origin-height=&quot;217&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YFQw2/dJMcaiDj3lG/n7SA6SPULyhQ3LHbUfsHA0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YFQw2/dJMcaiDj3lG/n7SA6SPULyhQ3LHbUfsHA0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YFQw2/dJMcaiDj3lG/n7SA6SPULyhQ3LHbUfsHA0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYFQw2%2FdJMcaiDj3lG%2Fn7SA6SPULyhQ3LHbUfsHA0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;426&quot; height=&quot;217&quot; data-origin-width=&quot;426&quot; data-origin-height=&quot;217&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Salt and Pepper noise는 이미지에 흰 점 또는 검은 점이 무작위로 튀는 noise이다. 매우 갑작스러운 값의 변화가 생기고 일부 픽셀이 거의 0 또는 255같은 극단값으로 바뀌는 현상이 발생한다. 이에 대한 해결방안으로 3가지가 있다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Low pass filtering&lt;/li&gt;
&lt;li&gt;Median filtering&lt;/li&gt;
&lt;li&gt;Outlier rejection method&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 중 Median filtering에 대해 알아보자. Median filtering의 과정은 간단하다. 예시로 어떤 픽셀 주변에 3 x 3 window를 잡는다고 하자. 이 window에 대해서, 다음과 같은 작업을 수행한다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;주변 픽셀 값들을 모은다.&lt;/li&gt;
&lt;li&gt;값을 크기순으로 정렬한다.&lt;/li&gt;
&lt;li&gt;가운데 값, 즉 median을 선택한다.&lt;/li&gt;
&lt;li&gt;현재 픽셀 값을 그 median값으로 변경한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 3 x 3 window의 픽셀값을 정렬한 결과가 다음과 같다고 가정하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;50&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;52&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;57&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;58&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;60&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;61&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;63&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;65&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;255&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여기서 255는 salt noise일 것이다. 그리고 값은 60으로 변경해주면 된다. 참 쉽다.&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Gaussian Noise&amp;nbsp;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Gaussian noise는 salt and pepper와 달리 이미지 전체에 비교적 자연스럽게 퍼지는 noise이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Gaussian noise는 additive noise를 가정한다. Additive noise란, 원래 픽셀 값을 완전히 바꾸는 것이 아니라, 원래 픽셀 값에 어떤 랜덤한 noise 값을 더하는 형태를 말한다. 또한 평균을 0으로 가정한다. 아래와 같이 표현할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;274&quot; data-origin-height=&quot;32&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dA1MDs/dJMcaiDj3At/pQdPQr7kcx6DzRdteTOTW0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dA1MDs/dJMcaiDj3At/pQdPQr7kcx6DzRdteTOTW0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dA1MDs/dJMcaiDj3At/pQdPQr7kcx6DzRdteTOTW0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdA1MDs%2FdJMcaiDj3At%2FpQdPQr7kcx6DzRdteTOTW0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;274&quot; height=&quot;32&quot; data-origin-width=&quot;274&quot; data-origin-height=&quot;32&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;2516&quot; data-start=&quot;2496&quot;&gt;&lt;span&gt;&lt;span aria-hidden=&quot;true&quot;&gt;&lt;span&gt;&lt;span&gt;I&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;: 원래 이미지&lt;/li&gt;
&lt;li data-end=&quot;2545&quot; data-start=&quot;2517&quot;&gt;&lt;span&gt;&lt;span&gt;N(x,y)&lt;/span&gt;&lt;/span&gt;: Gaussian noise&lt;/li&gt;
&lt;li data-end=&quot;2576&quot; data-start=&quot;2546&quot;&gt;&lt;span&gt;&lt;span&gt;IG(x,y)&lt;/span&gt;&lt;/span&gt;: noise가 추가된 이미지&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 Gaussain noise의 제거에는 average filter가 사용된다. Average filter가 왜 효과가 좋을까? 만약 같은 장면을 noise가 섞인 상태로 100장 찍었다고 가정하자&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;259&quot; data-origin-height=&quot;31&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HrOmm/dJMcadvbvua/6YdFIXkOi4zmShQs4vH8XK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HrOmm/dJMcadvbvua/6YdFIXkOi4zmShQs4vH8XK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HrOmm/dJMcadvbvua/6YdFIXkOi4zmShQs4vH8XK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHrOmm%2FdJMcadvbvua%2F6YdFIXkOi4zmShQs4vH8XK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;259&quot; height=&quot;31&quot; data-origin-width=&quot;259&quot; data-origin-height=&quot;31&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 이미지들을 평균내면&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;379&quot; data-origin-height=&quot;71&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bgYN9b/dJMcafs3RFy/a5gRBQktEyo8RLTcNeDno0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bgYN9b/dJMcafs3RFy/a5gRBQktEyo8RLTcNeDno0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bgYN9b/dJMcafs3RFy/a5gRBQktEyo8RLTcNeDno0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbgYN9b%2FdJMcafs3RFy%2Fa5gRBQktEyo8RLTcNeDno0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;379&quot; height=&quot;71&quot; data-origin-width=&quot;379&quot; data-origin-height=&quot;71&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원래 이미지 값인 I는 계속 같은 값이니까 평균을 내도 그 값이 그대로 유지가 되는 반면에 noise에 해당하는 N는 랜덤하고 평균이 0이므로, 큰 수의 법칙에 따라 많은 시행이 일어날 수록 N의 평균은 0에 수렴하게 된다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;760&quot; data-origin-height=&quot;427&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhJPAQ/dJMcahxFG6X/EB6GJM9OCJXsrIGP1ls750/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhJPAQ/dJMcahxFG6X/EB6GJM9OCJXsrIGP1ls750/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhJPAQ/dJMcahxFG6X/EB6GJM9OCJXsrIGP1ls750/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbhJPAQ%2FdJMcahxFG6X%2FEB6GJM9OCJXsrIGP1ls750%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;760&quot; height=&quot;427&quot; data-origin-width=&quot;760&quot; data-origin-height=&quot;427&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 noisy image 10장을 평균낸 것보다 100장을 평균낸 것이 더 깨끗하게 보인다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나, 현실에서는 같은 장면을 100장 가지고 있는 경우가 많지 않다. 그래서 한 장의 이미지 내부에서 주변 픽셀들을 평균내는 방식인 simple average filtering을 주로 사용한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Adaptive filtering&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Wiener Filter&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Average filter의 문제는 모든 영역에 똑같이 평균을 적용한다는 점이다. 그런데 이미지에는 두 종류의 영역이 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;변화가 거의 없는 smooth region&lt;/li&gt;
&lt;li&gt;변화가 큰 edge region&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Smooth region에서는 평균을 많이 내도 괜찮다. 어차피 원래도 비슷한 값들이 모여있기 때문이다. 그러나, edge region에서는 평균을 많이 내면 경계가 모호해지는 문제가 발생한다. 그래서 Wiener filter는 지역적인 특성을 보고 필터링 강도를 조절한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 그 지역적인 특성을 어떻게 보느냐? 바로, mask 내부의 평균과 분산을 사용한다. 분산이 크다는 건 주변 픽셀 값들이 많이 다르다는 의미이다. 즉, 경계나 디테일이 있을 가능성이 높으므로, 이런 곳에서는 평균을 강하게 적용하면 edge가 방가지므로, 원래 입력 값을 더 많이 유지해야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면, 분산이 작다는 건 주변 픽셀 값들이 비슷하다는 의미이다. 이런 곳에서는 평균을 많이 적용해도 구조가 크게 망가지지 않기 때문에 noise 제거를 더 강하게 해도 된다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Bilateral Filter&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Bilateral filter는 두 가지를 동시에 본다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;공간적으로 가까운가?&lt;/li&gt;
&lt;li&gt;픽셀 값이 비슷한가?&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 식이 위 2가지 가중치를 곱한 형태이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;562&quot; data-origin-height=&quot;86&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sPpPm/dJMcaglck4E/Mui2N5v0wlG4Ydac60sQ6K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sPpPm/dJMcaglck4E/Mui2N5v0wlG4Ydac60sQ6K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sPpPm/dJMcaglck4E/Mui2N5v0wlG4Ydac60sQ6K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsPpPm%2FdJMcaglck4E%2FMui2N5v0wlG4Ydac60sQ6K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;562&quot; height=&quot;86&quot; data-origin-width=&quot;562&quot; data-origin-height=&quot;86&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫 번째 Gaussian은 위치 차이를 본다. 두 번째 Gaussian은 intensity 차이를 본다. 즉, Bilateral filter는 가까이 있으면서, 밝기 값도 비슷한 픽셀만 많이 평균을 내는 방식으로 동작한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Nonlocal Means Filtering, NLM&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NLM은 앞의 필터들과 관점이 조금 다르다. 앞서 살펴보았던 filter들은 보통 현재 픽셀 주변의 local window를 중심으로 생각했다. 그러나 NLM은 이름 그대로 non-local, 즉 멀리 떨어진 영역까지 본다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>CS/영상처리</category>
      <author>PiLove</author>
      <guid isPermaLink="true">https://pi-love0314.tistory.com/59</guid>
      <comments>https://pi-love0314.tistory.com/entry/%EC%98%81%EC%83%81%EC%B2%98%EB%A6%AC-Image-Restoration#entry59comment</comments>
      <pubDate>Fri, 15 May 2026 08:42:41 +0900</pubDate>
    </item>
    <item>
      <title>[데이터베이스] Week8. 확장 ER Modeling, ER Model to Relation schema</title>
      <link>https://pi-love0314.tistory.com/entry/%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4-Week8-%ED%99%95%EC%9E%A5-ER-Modeling-ER-Model-to-Relation-schema</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;충남대학교 이규철 교수님, 데이터베이스 수업 8주차 강의 정리입니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Enhanced(Extended) ER Modeling&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ER Model로는 표현 못하는 것들이 많아, 더 확장한 모델을 EER(Enhanced ER) Model이라고 부른다. 기존 ER model에 대해 객체 지향 개념도 추가 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체 지향 개념이 추가되면서 ER model에 새로운 타입이 추가되었는데, 먼저 상속 관계성 타입이다. 서브 클래스 - 수퍼 클래스 관계성 타입으로, is - a 타입이라고도 부른다. 두 개체 클래스(서브 클래스, 수퍼 클래스) 사이의 일대일 관계성 타입을 표현하는 타입으로, 서브 클래스는 수퍼 클래스의 모든 속성을 가지면서 추가적인 특성 또한 가질 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;667&quot; data-origin-height=&quot;313&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cdei5T/dJMcafsQJd1/O4paAd8rYhztn5u96a5y9k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cdei5T/dJMcafsQJd1/O4paAd8rYhztn5u96a5y9k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cdei5T/dJMcafsQJd1/O4paAd8rYhztn5u96a5y9k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcdei5T%2FdJMcafsQJd1%2FO4paAd8rYhztn5u96a5y9k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;667&quot; height=&quot;313&quot; data-origin-width=&quot;667&quot; data-origin-height=&quot;313&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음과 같은 그림에 대하여, Hourly Employee와 Slaried Employee는 Employee라는 수퍼 클래스의 서브클래스이다. 위에서 서술 하였듯이, 서브 클래스는 수퍼 클래스의 속성을 모두 가지며, 추가적인 속성을 가지고 있는 것을 확인할 수 있다. is - a 타입이라고도 부른다고 했는데, Hourly Employee is an Employee 라는 관계로 나타낼 수 있기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 Specialization, Genralization이라는 개념에 대해 간단하게 소개하자면, 모델링을 하는 과정에서 한 클래스 내의 객체들 간의 차이점을 발견하고 명세하는 과정을 Specialization(Top-Down)이라고 한다. 그리고, 두 개 또는 그 이상의 분리된 클래스들에서 하나의 공통된 속성들을 가지는 수퍼 클래스를 생성하는 과정을 Generalization(Bottom-Up)이라고 한다. 모델링은 어느 방향으로 하든 상관 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Specialization은 다중 계층 구조를 가질 수 있는데, 예를 하나 살펴보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;822&quot; data-origin-height=&quot;296&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/buIkBh/dJMcadPhRFf/VQvfA6hFeHb73Tq3OQzNH0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/buIkBh/dJMcadPhRFf/VQvfA6hFeHb73Tq3OQzNH0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/buIkBh/dJMcadPhRFf/VQvfA6hFeHb73Tq3OQzNH0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbuIkBh%2FdJMcadPhRFf%2FVQvfA6hFeHb73Tq3OQzNH0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;822&quot; height=&quot;296&quot; data-origin-width=&quot;822&quot; data-origin-height=&quot;296&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Specialization을 할 때 &lt;b&gt;특정 측면에 따라&lt;/b&gt; Specialization이 가능하다. 무슨 의미냐면, 위 그림의 왼쪽 브랜치를 보자. Employee가 돈을 어떤 형태로 받느냐에 따라 Hourly, Salaried로 구분이 가능하다. 반면, 오른쪽 브랜치를 보자. Employee의 업무에 따라 Cashier, Secretary, Shipping Clerk, Stock Clerck으로 구분 가능하다. 즉, 측면에 따라 다른 Specialization이 가능하고, 이를 Multiple Specialization(다중 특수화) 구조라고 부른다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이와 헷갈리면 안되는 개념으로 Multiple Inheritance(다중 상속) 구조가 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;481&quot; data-origin-height=&quot;291&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cfKjdU/dJMcaakMuVs/ORY1iMKh5z5tMwmFjFmqs0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cfKjdU/dJMcaakMuVs/ORY1iMKh5z5tMwmFjFmqs0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cfKjdU/dJMcaakMuVs/ORY1iMKh5z5tMwmFjFmqs0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcfKjdU%2FdJMcaakMuVs%2FORY1iMKh5z5tMwmFjFmqs0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;481&quot; height=&quot;291&quot; data-origin-width=&quot;481&quot; data-origin-height=&quot;291&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Multiple Inheritance 구조에서는 2개의 수퍼 클래스로부터 하나의 서브 클래스가 나오게 된다. 만약 서로 다른 두 수퍼 클래스에 같은 이름을 가진 속성이 있다면, 서브 클래스에는 속성이 구분되어 저장된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금까지 구조, 즉 Structure에 대해 알아보았다. 이제 EER model의 constraint에 대해 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Constraint는 3가지를 명시할 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;상호배제(Disjointness)&lt;br /&gt;: 하나의 개체는 반드시 하나의 서브클래스에만 속해야 한다는 특성&lt;/li&gt;
&lt;li&gt;완전성(Completeness)&lt;br /&gt;: 하나의 개체는 적어도 하나의 서브 클래스에 속해야 한다는 특성&lt;/li&gt;
&lt;li&gt;특수화에 대한 정의 애트리뷰트(Definiting Attribute)&lt;br /&gt;: 애트리뷰트에 의해 정의된 특수화(speicalization)는 특정 애트리뷰트의 값을 통해 서브 클래스 멤버가 지정&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;834&quot; data-origin-height=&quot;331&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdbVuT/dJMcah5iBO8/Jxp4TKoTVEukGpYiUlfz10/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdbVuT/dJMcah5iBO8/Jxp4TKoTVEukGpYiUlfz10/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdbVuT/dJMcah5iBO8/Jxp4TKoTVEukGpYiUlfz10/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdbVuT%2FdJMcah5iBO8%2FJxp4TKoTVEukGpYiUlfz10%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;834&quot; height=&quot;331&quot; data-origin-width=&quot;834&quot; data-origin-height=&quot;331&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 부터 처음 왼쪽의 브랜치와 오른쪽의 브랜치를 보면, 그 줄기가 다른 것을 확인할 수 있다. 왼쪽은 2개의 줄로 표시된 total, 오른쪽은 1개의 줄로 표시된 partial이다. 지난번 시간에 배웠던 내용이기도 하다. 이를 통해 완전성 제약조건을 나타낼 수 있다. 왼쪽 브랜치를 먼저 보자. Employee는 Hourly나 Slaried 중 적어도 하나의 서브 클래스에 속해야 하므로 total participation constraint를 만족하고 이는 Completness constraint(완전성 제약조건)를 만족한다는 의미이다. 반대로 오른쪽 브랜치를 보자. 부분 특수화 라고 표현하였는데, 이는 partial participation을 의미하며, Employee가 업무에 따라 Cahiser, Secretary, Shipping clerk, Stock clerck으로 나눌 수 있는데, 이 외에도 Employee가 존재할 수 있다는 의미이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 왼쪽 브랜치는 d라고 표시되어 있고 오른쪽 브랜치는 o라고 표시되어 있는데, d는 Disjoint라는 의미이며, Employee는 Hourly Emplyee와 Slaried Employee로 딱 나뉘어짐을 의미한다. 다시 말해, Hourly이면서 Slaried인 Employee가 없다는 의미이다. 오른쪽 브랜치의 o는 Overlap이라는 의미이며, Employee는 Cashier이면서 Secretary인 Employee가 있을 수도 있으며, 그 외에도 서로 업무가 겹칠 수 있다는 의미이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 Defining attribute이다. Defining attribute는 각 개체의 특수화 방향을 정해주는 attribute이다. 위에서 살펴보았듯이, 특수화는 측면에 따라서 방향이 달라질 수 있는데, wageType이라는 Defining attribute를 두어 해당 속성의 값을 통해 Hourly이냐 Slaried이냐가 정해진다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;EER Model to Relation schema&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EER Model을 relation schema로 표현하는 방법은 크게 3가지이다.&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;슈퍼 클래스와 서브 클래스 각각에 대해 하나씩의 테이블을 생성한다.&lt;/li&gt;
&lt;li&gt;모든 서브 클래스의 애트리뷰트를 포함하여 슈퍼클래스에 대해서만 하나의 테이블을 생성한다.&lt;/li&gt;
&lt;li&gt;각 서브 클래스가 슈퍼 클래스의 애트리뷰트를 상속받아, 각 서브클래스에 대해서만 하나씩의 테이블을 생성한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좀더 쉽게 말하면,&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;슈퍼, 서브 각각 생성&lt;/li&gt;
&lt;li&gt;서브의 애트리뷰트를 포함하여 슈퍼 하나만 생성&lt;/li&gt;
&lt;li&gt;슈퍼의 애트리뷰트를 포함하여 서브 각각에 대해서만 생성&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;으로 이해하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>CS/데이터베이스</category>
      <author>PiLove</author>
      <guid isPermaLink="true">https://pi-love0314.tistory.com/57</guid>
      <comments>https://pi-love0314.tistory.com/entry/%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4-Week8-%ED%99%95%EC%9E%A5-ER-Modeling-ER-Model-to-Relation-schema#entry57comment</comments>
      <pubDate>Tue, 28 Apr 2026 14:46:25 +0900</pubDate>
    </item>
    <item>
      <title>[데이터통신] Week7. Digital Transmission</title>
      <link>https://pi-love0314.tistory.com/entry/%EB%8D%B0%EC%9D%B4%ED%84%B0%ED%86%B5%EC%8B%A0-Week7-Digital-Transmission</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;충남대학교 김기일 교수님, 데이터통신 과목 7주차 강의 내용 정리입니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Digital to Digital Conversion&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Digital data를 어떻게 Digital signal로 변경할 수 있을까? 변환은 Line coding과 Block coding을 통해 가능하며, Line coding은 항상 이루어지지만, Block coding은 항상 이루어지진 않는다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Line coding&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1194&quot; data-origin-height=&quot;308&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbFkhl/dJMcaibUhiS/DDMwqLkY7B7fxkodSWxlOk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbFkhl/dJMcaibUhiS/DDMwqLkY7B7fxkodSWxlOk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbFkhl/dJMcaibUhiS/DDMwqLkY7B7fxkodSWxlOk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbFkhl%2FdJMcaibUhiS%2FDDMwqLkY7B7fxkodSWxlOk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1194&quot; height=&quot;308&quot; data-origin-width=&quot;1194&quot; data-origin-height=&quot;308&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Line coding은 bit와 signal element를 맵핑하여 문제를 풀어가는 방식을 말한다. 무슨 말이냐? 아래 그림을 살펴보면서 알아가자.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Data element per Signal element (r)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Digital data를 Signal data로 변환하는 과정에서 중요하게 생각해볼만한 것이 Data rate와 Signal rate이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1042&quot; data-origin-height=&quot;745&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cGHAtR/dJMcahxidbo/OzeepZQOKiQlIyN6DU86K0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cGHAtR/dJMcahxidbo/OzeepZQOKiQlIyN6DU86K0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cGHAtR/dJMcahxidbo/OzeepZQOKiQlIyN6DU86K0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcGHAtR%2FdJMcahxidbo%2FOzeepZQOKiQlIyN6DU86K0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1042&quot; height=&quot;745&quot; data-origin-width=&quot;1042&quot; data-origin-height=&quot;745&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 그림을 보면, &quot;속도&quot; 도 크게 두 가지로 나눌 수 있다. 하나는 Data rate, 또 하나는 Signal rate이다. Data rate는 우리가 지금까지 배웠던 것 처럼 초당 보내는 데이터 비트 수 즉, bps로 표현할 수 있고, Signal rate는 초당 보내는 signal element의 수, 단위는 baud로 표현할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금까지 배웠던 내용에 의하면 bps가 높을수록 좋았다. 그렇다면, baud는 높을수록 좋을까? 낮을수록 좋을까? 정답은 낮을수록 좋다. Baud가 낮다는 의미는 무슨 의미일까? 1초 동안 signal이 바뀌는 횟수가 적다는 의미이다. 즉, 대역폭의 영역이 줄어든다는 의미이다. 지난 번에 배웠던 내용을 생각해보자. Signal이 빠르게 바뀐다는 건, 시간축에서 더 짧은 시간 안에 모양이 급격하게 변한다는 의미이고, 이러한 급한 변화는 빠르게 진동하는 주파수 성분이 필요하다. 결국, signal이 빠르게 변화하기 위해선 더 높은 주파수 성분이 필요하고 이는 곧 넓은 대역폭을 의미하게 된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 데이터통신에서는 bps는 높게, baud는 낮게하는 것이 목표라고 할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;697&quot; data-origin-height=&quot;63&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GuQvN/dJMcaffcvcT/DUTha4FApNDP0JAVBUZQY0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GuQvN/dJMcaffcvcT/DUTha4FApNDP0JAVBUZQY0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GuQvN/dJMcaffcvcT/DUTha4FApNDP0JAVBUZQY0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGuQvN%2FdJMcaffcvcT%2FDUTha4FApNDP0JAVBUZQY0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;697&quot; height=&quot;63&quot; data-origin-width=&quot;697&quot; data-origin-height=&quot;63&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 식에 대하여 N : data rate, S : signal rate, r : signal element 하나가 담는 data element 수를 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 공식 바로 위의 그림에서 r의 값을 함께 표현하기도 했는데, 이 r이 signal을 평가하는 하나의 척도로 볼 수 있다. r이 크면 한 신호에 더 많은 데이터를 담을 수 있다. 따라서 signal rate가 작아진다. 반면 r이 작으면 비트 하나를 보내는 데 여러 신호를 써야한다. 결국 signal rate가 커진다. 즉, r은 클수록 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;b&gt;이 r값과 더불어 DC component, Self synchronization을 고려하여 적절한 신호 형태를 설계하는 것을 Line coding이라고 부른다.&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;DC Component problem&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Line coding에서 생길 수 있는 문제 중 DC component라는 게 있다. 아래 2개 중 하나만 만족하더라도 Digital signal이 DC Component problem을 가지고 있는 것으로 본다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Digital signal에서 전압이 오랫동안 한쪽으로 constant하게 치우쳐져 있다.&lt;/li&gt;
&lt;li&gt;Digital signal의 평균 전압이 0이 아니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;699&quot; data-origin-height=&quot;410&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bs57K4/dJMcaaroI1S/LwGjHmF9umrJ84UuBMIktK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bs57K4/dJMcaaroI1S/LwGjHmF9umrJ84UuBMIktK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bs57K4/dJMcaaroI1S/LwGjHmF9umrJ84UuBMIktK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbs57K4%2FdJMcaaroI1S%2FLwGjHmF9umrJ84UuBMIktK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;699&quot; height=&quot;410&quot; data-origin-width=&quot;699&quot; data-origin-height=&quot;410&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2개의 그래프 중 위 그래프는 평균 전압이 0이 아니므로, DC component를 가지고 있다고 볼 수 있다, 아래 그래프는 평균 전압이 0이지만, 전압이 한쪽으로 constant하게 치우쳐질 수 있는 위험이 있으므로 여전히 DC component를 가지고 있다고 볼 수 있다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Self-synchronization problem&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Line coding에서 생길 수 있는 또 다른 문제로 Self synchronization라는 게 있다. 송신측은 자신의 클럭에 맞추어 비트를 보내고, 수신측도 자신의 클럭에 맞추어 비트를 읽는다. 이때, 두 클럭이 완벽히 같을 수는 없다. 그래서 수신측은 signal을 통해 현재 비트의 위치를 알 수 있어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, Digital signal은 signal 안에 타이밍 정보가 포함되어 수신측에서 그 신호의 transition(전이)을 보고 클럭을 다시 맞출 수 있는 성질인 self-synchronization을 가지고 있어야 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;962&quot; data-origin-height=&quot;456&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uEX0W/dJMcahYlbRu/JaaResKpZ1s2nko1O15io1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uEX0W/dJMcahYlbRu/JaaResKpZ1s2nko1O15io1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uEX0W/dJMcahYlbRu/JaaResKpZ1s2nko1O15io1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuEX0W%2FdJMcahYlbRu%2FJaaResKpZ1s2nko1O15io1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;962&quot; height=&quot;456&quot; data-origin-width=&quot;962&quot; data-origin-height=&quot;456&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 그림은 self synchronization이 없다고 볼 수 있다. 위에서 언급했듯이 송신기와 수신기는 각자의 클럭에 맞게 비트를 읽어내는데, 송신기에서 보낸 signal에 주기적인 전이(transition)이 없으므로 수신기에서 비트를 잘못 읽어낸 것이다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Line coding의 종류&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;747&quot; data-origin-height=&quot;237&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b4OJSF/dJMcabcJBkR/f54dR7traIrfnAH1wEMqAk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b4OJSF/dJMcabcJBkR/f54dR7traIrfnAH1wEMqAk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b4OJSF/dJMcabcJBkR/f54dR7traIrfnAH1wEMqAk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb4OJSF%2FdJMcabcJBkR%2Ff54dR7traIrfnAH1wEMqAk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;747&quot; height=&quot;237&quot; data-origin-width=&quot;747&quot; data-origin-height=&quot;237&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Unipolar&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Unipolar는 말 그대로 전압이 한쪽 극성만 사용되는 방식이다. 안타깝게도 DC component가 존재하고, Self synchronization은 없다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;731&quot; data-origin-height=&quot;216&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bvfUg3/dJMcafGe7Fv/XjRdMH6YkxojZdJELjBKhK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvfUg3/dJMcafGe7Fv/XjRdMH6YkxojZdJELjBKhK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvfUg3/dJMcafGe7Fv/XjRdMH6YkxojZdJELjBKhK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbvfUg3%2FdJMcafGe7Fv%2FXjRdMH6YkxojZdJELjBKhK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;731&quot; height=&quot;216&quot; data-origin-width=&quot;731&quot; data-origin-height=&quot;216&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Polar : NRZ(Non Return to Zero)&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;774&quot; data-origin-height=&quot;257&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b8Vp1W/dJMcaiCWe0R/1KPRrnACK9Xma4v6vDERK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b8Vp1W/dJMcaiCWe0R/1KPRrnACK9Xma4v6vDERK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b8Vp1W/dJMcaiCWe0R/1KPRrnACK9Xma4v6vDERK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb8Vp1W%2FdJMcaiCWe0R%2F1KPRrnACK9Xma4v6vDERK1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;774&quot; height=&quot;257&quot; data-origin-width=&quot;774&quot; data-origin-height=&quot;257&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NRZ-L의 경우, DC component가 없다고는 못한다. 평균은 0이지만, 전압이 한쪽으로 치우치면 DC component가 발생할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NRZ-I의 경우에도, DC component의 위험이 있다. 그래도 Inversion 덕분에 bit가 1이 발생할 때에 한하여 전이(Transition)가 발생하므로 한정적으로 Self synchronization이 있다곤 볼 수 있다. 물론 완벽하지 않다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Polar : RZ(Return to Zero)&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;673&quot; data-origin-height=&quot;217&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cK8FTm/dJMcafztQjG/jKwPe5AzQLn6GZFRT8MKY1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cK8FTm/dJMcafztQjG/jKwPe5AzQLn6GZFRT8MKY1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cK8FTm/dJMcafztQjG/jKwPe5AzQLn6GZFRT8MKY1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcK8FTm%2FdJMcafztQjG%2FjKwPe5AzQLn6GZFRT8MKY1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;673&quot; height=&quot;217&quot; data-origin-width=&quot;673&quot; data-origin-height=&quot;217&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 경우에도 중간에 전압이 0으로 돌아오면서 전압이 상수로 일정하게 이어질 걱정은 안해도 된다. 평균도 0이므로, DC component는 없다고 보면된다. 0으로 돌아오는 지점이 비트의 중간 부분이므로 타이밍도 전달이 된다. 따라서 Self synchronization이 있다고 볼 수 있다. 그러나 r 값이 안타깝게도 1/2이다. 따라서 필요한 Bandwidth도 2배이다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Polar : Manchester and Differential Manchester&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;644&quot; data-origin-height=&quot;217&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZsQH1/dJMcagZqiig/vFQpxkrV1FIQsINy1qlfq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZsQH1/dJMcagZqiig/vFQpxkrV1FIQsINy1qlfq1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZsQH1/dJMcagZqiig/vFQpxkrV1FIQsINy1qlfq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZsQH1%2FdJMcagZqiig%2FvFQpxkrV1FIQsINy1qlfq1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;644&quot; height=&quot;217&quot; data-origin-width=&quot;644&quot; data-origin-height=&quot;217&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Manchester는 RZ와 다르게 0으로 보내지 않고, signal element 도중에 아예 다른 전압으로 signal을 변경한다. 덕분에 타이밍 정보가 수신기에 전달되므로 클럭을 비트에 맞출 수 있고, 따라서 synchronization을 만족한다. 또한 DC component도 없다고 볼 수 있다. 평균이 0이 될 것이고, 중간에 전압을 변경하기 때문에 상수로 일정하게 유지될 걱정도 없기 때문이다. 다만, RZ 처럼 signal element 당 bit의 수를 나타내는 r의 값이 1/2이기 때문에 Bandwidth를 2배로 사용해야 한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Bipolar : AMI and Pseudoternary&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;770&quot; data-origin-height=&quot;207&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dUNhVH/dJMcaaSulGt/4nljxMdSF8MvP0J8ULnER1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dUNhVH/dJMcaaSulGt/4nljxMdSF8MvP0J8ULnER1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dUNhVH/dJMcaaSulGt/4nljxMdSF8MvP0J8ULnER1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdUNhVH%2FdJMcaaSulGt%2F4nljxMdSF8MvP0J8ULnER1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;770&quot; height=&quot;207&quot; data-origin-width=&quot;770&quot; data-origin-height=&quot;207&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AMI는 0일 땐 0이고, 1일 땐 전압을 변경한다. 여기서 전압을 변경할 때, 이전 변경 방향과 반대로 방향을 함으로써 DC component 문제를 방지한다. 처음에 양의 방향으로 전압을 변경하다. 그 다음 1일 나올 때엔 음의 방향으로 전압을 변경한다. 그렇다면 synchronization은 어떠할까? synchronization은 제공하지 않는다. 대신 r 값이 1이 된다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Bipolar : Multilevel Schemes&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;712&quot; data-origin-height=&quot;286&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XNBtX/dJMcacQhvQF/W5sJ1O3kCDkmxSajFPpR1K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XNBtX/dJMcacQhvQF/W5sJ1O3kCDkmxSajFPpR1K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XNBtX/dJMcacQhvQF/W5sJ1O3kCDkmxSajFPpR1K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXNBtX%2FdJMcacQhvQF%2FW5sJ1O3kCDkmxSajFPpR1K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;712&quot; height=&quot;286&quot; data-origin-width=&quot;712&quot; data-origin-height=&quot;286&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;레벨을 여러개를 사용하게 되면 bps가 빨라진다. 즉, r값이 증가하는 이점을 얻는다. 대신 decoding과정이 복잡해지는 문제가 있다. 각각의 레벨을 나누어 송신하는 방법도 있다. 아래 그림을 참고하자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;747&quot; data-origin-height=&quot;320&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vyQfz/dJMcabqkw2K/5sGVxGsa9HIl32E9Dv2uRK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vyQfz/dJMcabqkw2K/5sGVxGsa9HIl32E9Dv2uRK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vyQfz/dJMcabqkw2K/5sGVxGsa9HIl32E9Dv2uRK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvyQfz%2FdJMcabqkw2K%2F5sGVxGsa9HIl32E9Dv2uRK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;747&quot; height=&quot;320&quot; data-origin-width=&quot;747&quot; data-origin-height=&quot;320&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Block coding&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Line coding의 방법만으로는 준수한 r값(bandwidth), DC component, Self synchronization을 모두 만족시키긴 어려웠고, 이를 보완하기 위해 block coding이 등장했다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;752&quot; data-origin-height=&quot;129&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BBUeB/dJMcacv0rpc/FEdSOmFS3JpKMgoM2gKV41/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BBUeB/dJMcacv0rpc/FEdSOmFS3JpKMgoM2gKV41/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BBUeB/dJMcacv0rpc/FEdSOmFS3JpKMgoM2gKV41/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBBUeB%2FdJMcacv0rpc%2FFEdSOmFS3JpKMgoM2gKV41%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;752&quot; height=&quot;129&quot; data-origin-width=&quot;752&quot; data-origin-height=&quot;129&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적으로 블록 코딩은 위와 같은 과정을 통해 진행한다. 기존 m개의 비트열을 더 긴 비트열인 n개 비트열로 만들어준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 통해 얻을 수 있는 효과는 뭐가 있을까? 예를 하나 들어보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;661&quot; data-origin-height=&quot;178&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dNcmcV/dJMcagFa5Zq/zxs0uzo0gFOGdcd5nWDTlk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dNcmcV/dJMcagFa5Zq/zxs0uzo0gFOGdcd5nWDTlk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dNcmcV/dJMcagFa5Zq/zxs0uzo0gFOGdcd5nWDTlk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdNcmcV%2FdJMcagFa5Zq%2Fzxs0uzo0gFOGdcd5nWDTlk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;661&quot; height=&quot;178&quot; data-origin-width=&quot;661&quot; data-origin-height=&quot;178&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NRZ-I라는 Line coding의 문제가 무엇이었는지 기억하는지용? 0이 계속 반복되면 DC component가 발생할 수 있다는 점이다. Block coding을 이용하면 이 부분을 해결할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;757&quot; data-origin-height=&quot;495&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b6ACpU/dJMcajaLyZk/rQzMoqSZwyKYwQQ3nu4Yc0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b6ACpU/dJMcajaLyZk/rQzMoqSZwyKYwQQ3nu4Yc0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b6ACpU/dJMcajaLyZk/rQzMoqSZwyKYwQQ3nu4Yc0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb6ACpU%2FdJMcajaLyZk%2FrQzMoqSZwyKYwQQ3nu4Yc0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;757&quot; height=&quot;495&quot; data-origin-width=&quot;757&quot; data-origin-height=&quot;495&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NRZ-I가 만약 0이 반복되는 4개의 비트열을 보냈다고 가정하면, 더 많은 비트열을 이어 붙여서 1이 나타나게끔 재포장하는 것이 즉, 0이 계속 나오는 게 문제면, 그 패턴이 그대로 나오지 않도록 먼저 block coding을 하고, 그 다음 NRZ-I로 보낸다&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Scrambling&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Line coding은 signal의 모양을 바꾸었다. Block coding은 데이터를 묶는 단위를 바꾸었다. Scrambling은 signal은 encoding할 때 signal을 바꾼다.&amp;nbsp;&lt;/p&gt;</description>
      <category>CS/데이터통신</category>
      <author>PiLove</author>
      <guid isPermaLink="true">https://pi-love0314.tistory.com/53</guid>
      <comments>https://pi-love0314.tistory.com/entry/%EB%8D%B0%EC%9D%B4%ED%84%B0%ED%86%B5%EC%8B%A0-Week7-Digital-Transmission#entry53comment</comments>
      <pubDate>Mon, 13 Apr 2026 19:27:20 +0900</pubDate>
    </item>
    <item>
      <title>[데이터베이스] Week6. 데이터 모델 및 개념적 설계</title>
      <link>https://pi-love0314.tistory.com/entry/%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4-Week6-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%AA%A8%EB%8D%B8-%EB%B0%8F-%EA%B0%9C%EB%85%90%EC%A0%81-%EC%84%A4%EA%B3%84</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;충남대학교 이규철 교수님, 데이터베이스 과목 6주차 강의 내용 정리입니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;데이터베이스 설계 단계&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1188&quot; data-origin-height=&quot;539&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bmqdQ4/dJMcacJtXD4/RKZ2eqh7hq5pDxHjvyIoF0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bmqdQ4/dJMcacJtXD4/RKZ2eqh7hq5pDxHjvyIoF0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bmqdQ4/dJMcacJtXD4/RKZ2eqh7hq5pDxHjvyIoF0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbmqdQ4%2FdJMcacJtXD4%2FRKZ2eqh7hq5pDxHjvyIoF0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1188&quot; height=&quot;539&quot; data-origin-width=&quot;1188&quot; data-origin-height=&quot;539&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터베이스 설계는 현실 세계의 요구사항을 분석하고 점차 구현 가능한 형태로 바꾸는 과정을 거친다. 설계 단계는 위 그림과 같다.&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;요구사항 수집 및 분석&lt;/li&gt;
&lt;li&gt;개념적 설계 : 현실을 사람이 이해하기 쉬운 개념 수준으로 표현하는 단계&lt;/li&gt;
&lt;li&gt;논리적 설계 : 관계형 테이블 같은 DBMS 구조로 바꾸는 단계&lt;/li&gt;
&lt;li&gt;물리적 설계 : 실제 저장장치에 어떻게 저장하고 접근할지 정하는 단계(ORACLE, SQL, ...&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Employee와 Project에 대한 실세계 데이터를 토대로 데이터베이스를 설계한다고 가정하자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1039&quot; data-origin-height=&quot;529&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mlUIE/dJMcadVRcHT/58cbNOeUlZKeDvkeclpRJ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mlUIE/dJMcadVRcHT/58cbNOeUlZKeDvkeclpRJ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mlUIE/dJMcadVRcHT/58cbNOeUlZKeDvkeclpRJ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmlUIE%2FdJMcadVRcHT%2F58cbNOeUlZKeDvkeclpRJ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1039&quot; height=&quot;529&quot; data-origin-width=&quot;1039&quot; data-origin-height=&quot;529&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실세계의 데이터는 하나의 사실로, 데이터에 불과하지만, 개념적 설계를 통해 이들 사이의 관계를 정의하고 각 개체가 가지는 속성을 정의한다. Employee는 ssn이라는 key를 가지고, Project는 pnumer라는 key를 가진다. 그리고 Employee와 Project의 관계(Relationship)를 Works로 정의하고, hours라는 속성을 가진다. 또한 한 직원이 여러 프로젝트에 참여할 수 있고, 하나의 프로젝트에도 여러 직원이 참여할 수 있으므로, 다대다 즉, M:N 구조이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1159&quot; data-origin-height=&quot;549&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/I4Aa8/dJMcacbCxkt/rS5nKOUJYoNLTu0My1Pvv1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/I4Aa8/dJMcacbCxkt/rS5nKOUJYoNLTu0My1Pvv1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/I4Aa8/dJMcacbCxkt/rS5nKOUJYoNLTu0My1Pvv1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FI4Aa8%2FdJMcacbCxkt%2FrS5nKOUJYoNLTu0My1Pvv1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1159&quot; height=&quot;549&quot; data-origin-width=&quot;1159&quot; data-origin-height=&quot;549&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;논리적 설계에서는 개념적 설계에서 만든 ER 모델을 실제 DB로 구현 가능한 형태로 바꾸는 작업을 수행한다. 개념적 설계의 결과인 ER Diagram을 Relational Schema로 변환해준다. 물리적 설계에서는 사용하는 DBMS의 종류에 따라 어떻게 저장하고 관리할지를 정하게 된다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;데이터 모델&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 모델은 개념적 설계 단계에서 현실세계의 데이터를 Abstratction하기 위해 사용하는 하나의 도구이다. 데이터 모델은 여러 종류가 있고, &lt;b&gt;Structure, Operation, Constraints&lt;/b&gt; 3개의 구성요소를 지닌다. 이 중 Operation은 실제로 개념적 설계 단계에서는 잘 사용하지 않는다. 오늘 배워 볼 모델은 ER Data model이다. &lt;b&gt;ER Data model 을 통해 개념적 설계를 하고, Relational Data model로 논리적인 설계를 하는 것이 목표이다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 언급했듯이, 개념적 데이터 모델에 해당하는 것이 ER Data model, 논리적 데이터 모델에 해당하는 것이 Relational Data model이다. 물리적 데이터 모델은 강의 내용에 따로 언급하지 않으셨다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;요구사항 수집과 분석&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요구사항을 수집하고 분석하는 단계이다. 매우 중요한 단계이지만, 공부할 내용은 따로 없으니 넘어가도록 하자.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;개체-관계 모델링(E-R Model)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;E-R(-A) Model(Entity-Relationship(-Attribute) Model)이라고 부른다. 데이터를 개체, 애트리뷰트, 관계성으로 기술하는 고수준의 데이터 모델로 이해하면 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1099&quot; data-origin-height=&quot;518&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IEKQf/dJMcaciownj/163EtgJOvn2BVoTZfT5jx1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IEKQf/dJMcaciownj/163EtgJOvn2BVoTZfT5jx1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IEKQf/dJMcaciownj/163EtgJOvn2BVoTZfT5jx1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIEKQf%2FdJMcaciownj%2F163EtgJOvn2BVoTZfT5jx1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1099&quot; height=&quot;518&quot; data-origin-width=&quot;1099&quot; data-origin-height=&quot;518&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;E-R Diagram으로 데이터를 표현한 하나의 예제이다. 개념적 설계의 결과물인 ER Schema라고도 한다. 사각형은 각각의 개체를 의미하고, 사각형 사이의 마름모는 개체 사이의 관계성을 의미한다. 단어가 갑자기 기억이 안나는데... 납작한 원형 모양의 도형은 속성을 나타내고, 2줄로 그려진 납작한 원형 모양의 도형은 다중값을 가지는 속성을 의미한다. 실선으로 그려진 납작한 원형 도형은 유도 속성이라고, 다른 속성으로부터 파생된 속성임을 뜻한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Attribute의 유형은 크게 Simple과 Composite으로 나눌 수 있다. 더 이상 나눌 수 없는 atomic한 attribute를 simple attribute라고 하고, 하나의 의미있는 속성이지만, 더 잘게 쪼갤 수 있는 attribute를 composite attribute라고 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;695&quot; data-origin-height=&quot;194&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oACWK/dJMcag6anMM/fDvRKTsgGw7KwNXAaV77zk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oACWK/dJMcag6anMM/fDvRKTsgGw7KwNXAaV77zk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oACWK/dJMcag6anMM/fDvRKTsgGw7KwNXAaV77zk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoACWK%2FdJMcag6anMM%2FfDvRKTsgGw7KwNXAaV77zk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;695&quot; height=&quot;194&quot; data-origin-width=&quot;695&quot; data-origin-height=&quot;194&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음과 같은 attribute가 있다고 할때, address, street은 composite attribute, 그 외의 attribute는 simple attribute라고 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 Stored attribute와 Derived attribute로도 나눌 수 있다. Age라는 attribute가 있다고 할 때, stored attribute로 사용한다고 하면, 각 개체의 나이가 증가할 때마다 업데이트를 해줘야한다. 그러나 derived attribute로 사용한다고 하면, birthday라는 attribute를 통해 현재 년도를 빼서 나이를 구할 수 있으므로 업데이트를 하지 않아도 된다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;E-R Diagram&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>CS/데이터베이스</category>
      <author>PiLove</author>
      <guid isPermaLink="true">https://pi-love0314.tistory.com/52</guid>
      <comments>https://pi-love0314.tistory.com/entry/%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4-Week6-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%AA%A8%EB%8D%B8-%EB%B0%8F-%EA%B0%9C%EB%85%90%EC%A0%81-%EC%84%A4%EA%B3%84#entry52comment</comments>
      <pubDate>Thu, 9 Apr 2026 17:43:17 +0900</pubDate>
    </item>
    <item>
      <title>[운영체제및실습] Week6-7. Deadlock and Starvation</title>
      <link>https://pi-love0314.tistory.com/entry/%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C%EB%B0%8F%EC%8B%A4%EC%8A%B5-Week6-7-Deadlock-and-Starvation</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;충남대학교 류재철 교수님, 운영체제및실습 과목 6~7주차 강의 정리입니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Philosophers problem&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Deadlock에 대해 알아보기 전에 Philosophers problem에 대해 알아보자.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;491&quot; data-origin-height=&quot;472&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bv2lef/dJMcahxdXLT/H3eKwkeSK6wYQv0s0CGzx1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bv2lef/dJMcahxdXLT/H3eKwkeSK6wYQv0s0CGzx1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bv2lef/dJMcahxdXLT/H3eKwkeSK6wYQv0s0CGzx1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbv2lef%2FdJMcahxdXLT%2FH3eKwkeSK6wYQv0s0CGzx1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;491&quot; height=&quot;472&quot; data-origin-width=&quot;491&quot; data-origin-height=&quot;472&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Philosophers problem이란, 5명의 철학자가 원형 테이블에 앉아 있고, 포크도 5개가 있는 상황을 가정하고, Deadlock을 흉내(?)낸 문제이다. 철학자는 생각하다가, 배가 고프면 본인 왼쪽 오른쪽 즉, 양쪽 포크 2개를 모두 집어야만 식사를 할 수 있다. 그리고 다 먹으면 포크를 내려 놓는다. 여기서 중요한 조건은 포크는 한번에 한 철학자만 사용이 가능하다는 점이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 철학자는 식사를 하려면 양쪽 포크를 다 집어야 한다. 그런데 만약 모든 철학자가 거의 동시에 행동해서, 왼쪽 포크만 먼저 집는 상황이 생길 수 있다. 이때 누군가 포크를 내려놓지 않으면 철학자 모두 영원히 오른쪽 포크를 기다려야하는 상황이 발생한다. 즉, Deadlock이 발생한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;843&quot; data-origin-height=&quot;555&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qvcbm/dJMcabcFf0f/ZQPMaYPzPSMvAZVOWwC17k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qvcbm/dJMcabcFf0f/ZQPMaYPzPSMvAZVOWwC17k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qvcbm/dJMcabcFf0f/ZQPMaYPzPSMvAZVOWwC17k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fqvcbm%2FdJMcabcFf0f%2FZQPMaYPzPSMvAZVOWwC17k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;843&quot; height=&quot;555&quot; data-origin-width=&quot;843&quot; data-origin-height=&quot;555&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이에 대한 교재의 첫 번째 솔루션이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저, fork라는 배열을 생성한다. 각각의 fork는 한번에 한명의 철학자만 집을 수 있으므로, 값은 1로 선언하고, fork의 개수는 총 5개이므로 5칸짜리 배열로 생성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음으로 philosopher 함수를 보자. 철학자는 먼저 생각하고, 자신의 앞에 놓인 fork[i]를 집는다. 그리고 다음 fork[(i+1) mod 5]를 집어야 하는데, 이때 문제가 발생할 수 있다. 만약, fork[i]를 5명의 철학자가 거의 동시에 집는다고 가정하자. 그러면 그 어떤 철학자도 fork[(i+1) mod 5]를 집을 수 없게 된다. 즉, Deadlock에 걸릴 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;802&quot; data-origin-height=&quot;586&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dOuH5j/dJMcacbA82I/9sWxaglTjcob274R8b9uL1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dOuH5j/dJMcacbA82I/9sWxaglTjcob274R8b9uL1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dOuH5j/dJMcacbA82I/9sWxaglTjcob274R8b9uL1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdOuH5j%2FdJMcacbA82I%2F9sWxaglTjcob274R8b9uL1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;802&quot; height=&quot;586&quot; data-origin-width=&quot;802&quot; data-origin-height=&quot;586&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;교재의 두 번째 솔루션을 확인해보자. 핵심 아이디어는 포크를 잡는 철학자의 수를 제한한다는 부분이다. 무슨 뜻이냐면, 문제의 Deadlock 상황은 5명의 철학자가 모두 왼쪽의 포크를 집었을 때 발생한다. 따라서, 애초에 동시에 포크를 잡을 수 있는 인원을 5명이 아니라 4명까지만 포크를 집도록 만든다는 의미이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드를 보면, room이라는 semaphore 변수를 하나 더 선언한다. 해당 room에는 4명의 철학자만 입장이 가능하므로, 값은 4로 초기화한다.&amp;nbsp; philosopher() 함수를 보면, 가장 먼저 wait(room)을 한다. 4명까지만 room에 입장이 가능하고, 마지막 한명은 입장이 불가능하다. 따라서 그 아래 코드가 실행될 때, 양쪽 fork를 모두 집은 철학자가 fork를 반납해야 입장이 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 외의 방법으로 2가지가 더 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 semaphore 변수 s를 선언하고 초기값을 1로 초기화한다. 그리고 가장 먼저 wait(s)를 하게 되면, 그 아래의 코드는 철학자 1명만 실행하게 된다. 이때 혼자이므로, fork를 양손 모두 집을 수 있으므로 식사를 마치고 자원을 반납하면 된다. 그러면 다음 철학자가 같은 과정을 거치게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막은 추가적인 semaphore를 사용하지 않는다. 철학자 중 홀수번째 철학자는 왼손을, 짝수번째 철학자는 오른손을 사용하게 하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>CS/운영체제및실습</category>
      <author>PiLove</author>
      <guid isPermaLink="true">https://pi-love0314.tistory.com/50</guid>
      <comments>https://pi-love0314.tistory.com/entry/%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C%EB%B0%8F%EC%8B%A4%EC%8A%B5-Week6-7-Deadlock-and-Starvation#entry50comment</comments>
      <pubDate>Tue, 7 Apr 2026 19:00:16 +0900</pubDate>
    </item>
    <item>
      <title>[운영체제및실습] Week5-6. Concurrency, Deadlock</title>
      <link>https://pi-love0314.tistory.com/entry/%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C%EB%B0%8F%EC%8B%A4%EC%8A%B5-Week5-%EC%9D%B4%EB%A1%A0-Concurrency</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;충남대학교 류재철 교수님, 운영체제 및 실습 과목 5주차 강의 내용 정리입니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Overview&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;752&quot; data-origin-height=&quot;596&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfgZJc/dJMcagLLMkC/ZmPXQbVFKVCC5mKmLI7Cc1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfgZJc/dJMcagLLMkC/ZmPXQbVFKVCC5mKmLI7Cc1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfgZJc/dJMcagLLMkC/ZmPXQbVFKVCC5mKmLI7Cc1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfgZJc%2FdJMcagLLMkC%2FZmPXQbVFKVCC5mKmLI7Cc1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;752&quot; height=&quot;596&quot; data-origin-width=&quot;752&quot; data-origin-height=&quot;596&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Atomic operation : 중간이 보이지 않는, 쪼개지지 않는 동작&lt;/li&gt;
&lt;li&gt;Critical section : 공유 자원 접근 구간&lt;/li&gt;
&lt;li&gt;Mutual exclusion : Critical section엔 한 번에 하나의 thread만 접근 가능&lt;/li&gt;
&lt;li&gt;Deadlock : 서로 기다리다가 영원히 멈춤&lt;/li&gt;
&lt;li&gt;Livelock : 계속 반응은 하는데 진전은 없음&lt;/li&gt;
&lt;li&gt;Starvation : 어떤 프로세스가 계속 선택되지 못함&lt;/li&gt;
&lt;li&gt;Race condition : 실행 순서 때문에 결과가 달라짐&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Critical-section problem&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 process나 thread가 공유 자원을 함께 쓰면 race condition이 발생할 수 있다. 따라서 공유 자원에 접근하는 코드 구간을 critical section으로 두고, 이 구간에 여러 실행 흐름이 어떻게 들어가야 하는지 규칙을 세우기로 했다. 그 규칙이 제대로 된 해법인지 판단하는 기준이 바로 &lt;b&gt;mutual exclusion, progress, bounded waiting&lt;/b&gt;이다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Mutual Exclusion&lt;br /&gt;한 순간에 오직 하나의 process/thread만 critical section에 들어갈 수 있어야 함&lt;/li&gt;
&lt;li&gt;Progress&lt;br /&gt;Critical section이 비어 있고, 들어가고 싶은 process/thread가 있다면 쓸데없이 무한정 기다리게 하면 안됨&lt;/li&gt;
&lt;li&gt;Bounded Waiting&lt;br /&gt;어떤 process가 critical section에 들어가고 싶다고 요청한 뒤, 언젠가는 들어갈 수 있어야 함&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 critical section problem을 설명할 때, 한 process 코드를 보통 4개의 구간으로 나누어 생각한다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Entry section&lt;br /&gt;Critical section에 진입하기 전 준비하는 부분&lt;/li&gt;
&lt;li&gt;Critical section&lt;br /&gt;실제 공유 자원에 접근하는 부분&lt;/li&gt;
&lt;li&gt;Exit section&lt;br /&gt;Critical section을 다 쓰고 나온 뒤 다른 process/thread가 들어올 수 있게 정리하는 부분&lt;/li&gt;
&lt;li&gt;Remainder section&lt;br /&gt;그 외의 공유자원과 상관없는 일반적인 코드&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 코드를 살펴보며 위 기준에 따라 해당 코드가 critical-section problem을 해결할 수 있는 해법이 될 수 있는지 판단해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고로, 단일 cpu일 경우, timeout을 염두해두고 코드를 보면 되고, 멀티 코어 cpu의 경우, 두 코드를 동시에 실행한다고 가정하면 된다. 일단 실습 환경이 core를 2개로 설정해두었기 때문에.. 멀티의 경우로 코드를 살펴보도록 하자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;574&quot; data-origin-height=&quot;233&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xZLE8/dJMcaadH66G/ce7IidP8JwSBdNlIQaLE11/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xZLE8/dJMcaadH66G/ce7IidP8JwSBdNlIQaLE11/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xZLE8/dJMcaadH66G/ce7IidP8JwSBdNlIQaLE11/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxZLE8%2FdJMcaadH66G%2Fce7IidP8JwSBdNlIQaLE11%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;574&quot; height=&quot;233&quot; data-origin-width=&quot;574&quot; data-origin-height=&quot;233&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PROCESS 0과 PROCESS 1이 동시에 실행된다고 가정하고, 초기의 turn값은 0이라고 가정하자. 이때, PROCESS 0 이 먼저 critical section에 진입하고, turn을 1로 만든 후 종료된다. 이후, PROCESS 1에서는 turn이 1이 되었으므로 무한 루프를 빠져나와 critical section에 접근하게 된다. 이는 mutual exclusion을 만족한다고 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나, 이 방법에는 문제가 있다. 만약 PROCESS 0 이 실행된 후 turn 값이 1이 되고 난 후에 PROCESS 1이 실행된다고 하자. 이 때, PROCESS 1은 critical section에 진입하고 싶지 않다고 하면, PROCESS 1은 entry section 자체를 수행하지 않을 것이다. 그리고 timeout에 의해 PROCESS 0 이 실행될텐데, 이때 PROCESS 0은 critical section에 진입하고 싶다고 하더라도 turn 값을 바꿔줄 PROCESS가 없으므로 critical section에 진입하지 못하게 된다. 즉, 위 코드는 Progress를 위반하게 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;559&quot; data-origin-height=&quot;252&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bU2GwF/dJMcaaEM6sZ/giETMjgLE3BWWwXdt0x3Lk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bU2GwF/dJMcaaEM6sZ/giETMjgLE3BWWwXdt0x3Lk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bU2GwF/dJMcaaEM6sZ/giETMjgLE3BWWwXdt0x3Lk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbU2GwF%2FdJMcaaEM6sZ%2FgiETMjgLE3BWWwXdt0x3Lk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;559&quot; height=&quot;252&quot; data-origin-width=&quot;559&quot; data-origin-height=&quot;252&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 코드는 First attempt의 문제를 고치려는 코드이다. flag[0], flag[1]의 초기값은 false로 가정한다. 아이디어는 상대의 flag를 확인하여, 상대가 critical section에 안들어오려는 것 같으면 통과하고, 그 다음에 내 flag를 true로 변경한 뒤 critical section에 들어간다. 이후 내 flag를 false로 변경해준다. 이렇게 하면, 상대방이 critical section에 진입하고 싶지 않다고 하더라도, flag를 변경해줄 필요가 없어서 자신은 critical section에 진입할 수 있게 되어 progress를 지킬 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나, 이 방법에도 문제가 있다. 두 process가 동시에 실행되고, flag[0]과 flag[1]의 초기값이 false로 가정하였기 때문에 동시에 critical section에 들어가버리는 일이 발생할 수도 있다. 즉, mutual exclusion을 위반하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단일 CPU 일 때도 마찬가지이다. PROCESS 0이 while을 통과한 후 timeout으로 CPU를 빼앗긴다. 이후 PROCESS 1도 while를 통과하고 flag[1] = true를 수행한 뒤, critical section에 진입하기 전에 다시 timeout이 발생한다고 하자. 그 다음 PROCESS 0이 다시 CPU를 받아 flag[0] = true를 수행하고 critical section에 진입할 수 있다. 이후 PROCESS 1도 다시 CPU를 받으면 이미 while(flag[0]) 검사는 통과한 상태이므로 그대로 critical section에 진입할 수 있다. 따라서 단일 CPU 환경에서도 interleaving에 의해 두 프로세스 모두 critical section에 들어갈 수 있으므로, 이 알고리즘은 mutual exclusion을 만족하지 못한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;516&quot; data-origin-height=&quot;228&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKek5M/dJMcadhbzFA/1Kz6wCkCgcSCDOkEfkKKOk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKek5M/dJMcadhbzFA/1Kz6wCkCgcSCDOkEfkKKOk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKek5M/dJMcadhbzFA/1Kz6wCkCgcSCDOkEfkKKOk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKek5M%2FdJMcadhbzFA%2F1Kz6wCkCgcSCDOkEfkKKOk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;516&quot; height=&quot;228&quot; data-origin-width=&quot;516&quot; data-origin-height=&quot;228&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 코드의 아이디어는 &quot;상대를 먼저 확인하지 말고, 일단 내가 들어가고 싶다는 표시부터 하자&quot;이다. 그래서 second attempt처럼 &quot;둘 다 상대 flag를 false로 보고 동시에 들어가 버리는 문제&quot;를 막으려는 것이다. 그래서 process가 critical section에 진입을 하고 싶다면, 자신의 flag를 true로 변경한뒤, critical section에 진입한다. 작업을 완료한 이후에는 자신의 flag를 false로 변경하여, 상대방의 진입 가능성도 열어둔다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데, 이것도 문제가 있다. 두 process가 거의 동시에 실행된다고 하자. 서로의 flag가 true로 변경되며, while문에 갇히게 될 수도 있다. 이렇게 기다리는 동안 누가 flag를 false로 변경해줄까? 조건으로 보면 mutual exclusion은 만족한다. 둘 다 동시에 critical section에 들어가지는 못하니까.. progress의 경우는 만족하지 못한다. critical secion이 비어 있음에도 둘 다 들어가고 싶어하는 상황에서 누구도 못들어가기 때문이다. Bounded waiting의 경우 당연히 보장하지 못한다. 애초에 while문에 묶여서 진입 자체가 멈춰버릴 수도 있으니까.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단일 CPU에 대해서도 동일한 문제가 발생할 수 있다. PROCESS 0에서 flag[0]을 true로 초기화하고 time out이 걸리면 PROCESS 1에서는 while문 안에 갇히게 된다. 그러면 무한루프를 계속 돌다가 다시 timeout이 걸리고 PROCESS 0으로 넘어갈텐데, 이때 flag[1]의 값은 true로 변경되어 있기 때문에 똑같이 무한루프에 갇히게 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;278&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cqSkkN/dJMcabXY74N/MqkfPpwiAzH6rVopzkeKJK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cqSkkN/dJMcabXY74N/MqkfPpwiAzH6rVopzkeKJK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cqSkkN/dJMcabXY74N/MqkfPpwiAzH6rVopzkeKJK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcqSkkN%2FdJMcabXY74N%2FMqkfPpwiAzH6rVopzkeKJK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;278&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;278&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Third attempt에서는 두 process가 while문에 갇혀서 둘 다 영원히 기다리는 상태가 됐었다. 이번에는 &quot;상대가 원하면 내가 잠깐 양보해서 flag를 flase로 만들고, 나중에 다시 시도하자&quot;가 아이디어이다. 다중 코어 CPU를 가정하면, 두 process가 동시에 실행되어, 서로의 flag를 동시에 false, true로 변경하게 되고... 똑같이 while문 안에 갇히게 된다. 단일 CPU를 가정해보자. PROCESS 0이 실행되고, flag[0]=true를 실행한 후, timeout에 걸린다고 하자. PROCESS 1에서 flag[1] = true로 변경하고 timeout이 걸린다고 하자. while문 안에서 또 flag[0] = true로 변경하고 다시 timeout에 걸리게 되면, PROCESS 1에서는 다시 while문을 돌아야하고... 이렇게 flag[0] = true, flag[1] = ture 를 수행한 후 timeout에 걸리게 되면 두 process 모두 critical section에 진입하지 못하게 된다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Semaphore&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Mutex, Progress, Bounded waiting과 같은 조건을 실제 코드에서는 어떻게 보장할까? 그 질문에 대한 답변이 바로 Semaphore이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Semaphore는 정수 값을 가지는 변수인데, 단 3가지의 연산만 허용된다. 초기화, semWait(감소), semSignal(증가)이다. semWait()은 보통 공유 자원에 들어가도 되나 확인하는 동작으로 보면 된다. 값을 1 감소시키고, 그 결과가 음수가 되면 지금 사용할 수 없는 자원이 없다는 뜻이라, 해당 프로세스를 ready queue에 넣고 block 시킨다. 반대로, semSignal()은 값을 1증가시키고, 기다리던 프로세스가 있다면 하나를 깨워 ready 상태로 보낸다. 코드로 이해해보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1294&quot; data-origin-height=&quot;881&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/svhGU/dJMcacQciGo/PsQ4DsfFFnKStvIKZEGSX1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/svhGU/dJMcacQciGo/PsQ4DsfFFnKStvIKZEGSX1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/svhGU/dJMcacQciGo/PsQ4DsfFFnKStvIKZEGSX1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsvhGU%2FdJMcacQciGo%2FPsQ4DsfFFnKStvIKZEGSX1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1294&quot; height=&quot;881&quot; data-origin-width=&quot;1294&quot; data-origin-height=&quot;881&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구조체로 선언된 semaphore에 대하여, count는 현재 사용 가능한 자원의 수를 의미하고, queue는 자원이 없어서 기다리는 프로세스들을 담는 queue이다. count는 개발자가 값을 지정할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;semWait()을 보면, 먼저 s.count-- 를 통해 자원을 하나 쓰겠다는 표시를 하고, 그 결과가 0보다 작아지면 큐에 집어 넣는다. 무슨 의미냐면... count가 현재 사용 가능한 자원의 수를 의미한다고 했는데, 이 count가 0보다 작아진다는 것은 사용 가능한 자원이 없다는 의미이고 따라서 해당 프로세스를 큐에 대기시킨다는 의미이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;semSignal()을 보면 s.count++ 를 통해 자원을 반납하겠다는 표시를 하고, 그 결과가 0보다 작거나 같으면, 큐에서 대기하고 있는 프로세스를 제거하고 ready 상태로 만든다. 무슨 의미냐면... count는 단순히 남아 있는 자원 수만을 의미하는 것이 아니다. semWait()의 코드를 보면, s.count-- 를 하고, 음수라면 큐에 프로세스를 담는다. 즉, count가 음수라면 큐에서 자원을 기다리고 있는 프로세스가 존재한다는 의미이다. 따라서 semSignal()을 실행하면 자원을 반납하고 큐에서 대기 중이던 프로세스가 자원을 점유할 수 있도록 ready 상태로 만드는 것까지 해야한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Deadlock&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Deadlock이란 2개 이상의 thread가 공유하는 특정 자원에 대하여, 서로가 서로 점유한 자원을 요구하며 무한정으로 대기하는 상황을 말한다. Deadlock의 조건에는 4가지가 있는데, 다음과 같다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;Mutex(상호배제)&lt;/b&gt;&lt;br /&gt;각각의 공유 자원은 한번에 하나의 thread만 점유 가능&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Hold and Wait(점유대기)&lt;/b&gt;&lt;br /&gt;특정 공유 자원을 점유한 상태에서 다른 공유 자원을 요구&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Non-preemption(비선점)&lt;br /&gt;&lt;/b&gt;이미 어떤 thread가 점유한 자원을 강제로 빼앗을 수 없어야 함&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Circular Wait(순환대기)&lt;br /&gt;&lt;/b&gt;Thread들이 원형으로 서로의 자원을 기다리는 상태&amp;nbsp;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 4가지 조건을 Coffman 조건이라고 하며, 4가지 조건을 모두 만족해야 deadlock이 성립한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Deadlock을 해결하기 위해서 OS(Kernel)는 예방, 회피, 탐지/회복, 무시 등의 방법을 수행한다.&lt;/p&gt;</description>
      <category>CS/운영체제및실습</category>
      <author>PiLove</author>
      <guid isPermaLink="true">https://pi-love0314.tistory.com/49</guid>
      <comments>https://pi-love0314.tistory.com/entry/%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C%EB%B0%8F%EC%8B%A4%EC%8A%B5-Week5-%EC%9D%B4%EB%A1%A0-Concurrency#entry49comment</comments>
      <pubDate>Tue, 31 Mar 2026 22:59:56 +0900</pubDate>
    </item>
    <item>
      <title>[데이터베이스] Week5. SQL-2</title>
      <link>https://pi-love0314.tistory.com/entry/%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4-Week5-%EC%9D%B4%EB%A1%A0-SQL-2</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;충남대학교 이규철 교수님, 데이터베이스 과목 5주차 강의 정리입니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;SQL에서 복잡한 검색 질의&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;[TABLE] JOIN [TABLE] ON [CONDITION]&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 개의 테이블에 대하여 질의를 할 때 하나의 테이블처럼 보기 위해 JOIN을 사용할 수 있다. 예시는 아래와 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1774954570925&quot; class=&quot;n1ql&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT *
FROM Employee, TimeCard
WHERE Employee.ssn = TimeCard.ssn;

SELECT *
FROM Employee JOIN TimeCard 
	ON Employee.ssn = TimeCard.ssn;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;789&quot; data-origin-height=&quot;204&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0ZAq6/dJMb996VEZe/arkRzolG84zKAKNqMKbp2K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0ZAq6/dJMb996VEZe/arkRzolG84zKAKNqMKbp2K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0ZAq6/dJMb996VEZe/arkRzolG84zKAKNqMKbp2K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0ZAq6%2FdJMb996VEZe%2FarkRzolG84zKAKNqMKbp2K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;789&quot; height=&quot;204&quot; data-origin-width=&quot;789&quot; data-origin-height=&quot;204&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;명령어 수행 결과, 두 개의 테이블을 동일한 ssn으로 묶어 하나의 테이블처럼 볼 수 있다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;집단화 함수&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;집단화 함수란, 여러 튜플의 정보를 하나의 튜플로 요약하는 데 사용하는 함수를 말한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;count, avg, sum, min, max, ... 등이 있다&lt;/li&gt;
&lt;li&gt;select 절이나 having 절에 사용된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1774954561034&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT COUNT(*)
FROM Rental
WHERE accountId = 101;

SELECT COUNT (DISTINCT lastName)
FROM Customer;

SELECT AVG((endTime-startTime)*24) as avghousWorked
FROM TimeCard;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;GROUP BY, HAVING&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GROUP BY 절은 grouping 하는 기준이 되는 attribute에 대하여 tuple들의 그룹을 구성하는 명령어이다. 아래 명령어를 살펴보자.&lt;/p&gt;
&lt;pre id=&quot;code_1774954944434&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT videoId, 
	AVG(cost) as averageCost,
	Count(*) as numRentals
FROM PreviousRental
GROUP BY videoId&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;과거 렌탈 정보를 가지고 있는 테이블에 대하여 videoId를 통해 grouping을 하되, 필요한 attribute로는 videoId, cost의 평균(averageCost), videoId 각각에 대한 튜플 개수(즉, 렌탈 횟수)이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;673&quot; data-origin-height=&quot;240&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cOsqA6/dJMcafswLLH/7d0AYFSK4411bQsQqasJxk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cOsqA6/dJMcafswLLH/7d0AYFSK4411bQsQqasJxk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cOsqA6/dJMcafswLLH/7d0AYFSK4411bQsQqasJxk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcOsqA6%2FdJMcafswLLH%2F7d0AYFSK4411bQsQqasJxk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;673&quot; height=&quot;240&quot; data-origin-width=&quot;673&quot; data-origin-height=&quot;240&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HAVING 절은 grouping attribute에 대한 조건절이라고 생각하면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1774955318046&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT title,
	genre,
    COUNT(*) as numRentals,
    AVG(cost) as avgCost,
    SUM(cost) as totalCost
FROM Movie, Videotape, PreviousRental
WHERE Movie.movieId = Videotape.movieId
	and Videotap.videoId = PreviousRental.videoId
GROUP BY Movie.movieId, title, genre
HAVING COUNT(*) &amp;gt;= 2&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 명령어에 대한 적용 순서는 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;770&quot; data-origin-height=&quot;290&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dlwwzG/dJMcai3Ob0s/ovsbvCC3T03mFhNg088rV0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dlwwzG/dJMcai3Ob0s/ovsbvCC3T03mFhNg088rV0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dlwwzG/dJMcai3Ob0s/ovsbvCC3T03mFhNg088rV0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdlwwzG%2FdJMcai3Ob0s%2FovsbvCC3T03mFhNg088rV0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;770&quot; height=&quot;290&quot; data-origin-width=&quot;770&quot; data-origin-height=&quot;290&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;770&quot; data-origin-height=&quot;235&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lfYoL/dJMcai3Ob0X/5AAYLWVL6gtK73TlttkTzK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lfYoL/dJMcai3Ob0X/5AAYLWVL6gtK73TlttkTzK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lfYoL/dJMcai3Ob0X/5AAYLWVL6gtK73TlttkTzK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlfYoL%2FdJMcai3Ob0X%2F5AAYLWVL6gtK73TlttkTzK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;770&quot; height=&quot;235&quot; data-origin-width=&quot;770&quot; data-origin-height=&quot;235&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;782&quot; data-origin-height=&quot;115&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xIErz/dJMcah4Yf1t/RTuGNVXv3IHXIjC2kXMbq0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xIErz/dJMcah4Yf1t/RTuGNVXv3IHXIjC2kXMbq0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xIErz/dJMcah4Yf1t/RTuGNVXv3IHXIjC2kXMbq0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxIErz%2FdJMcah4Yf1t%2FRTuGNVXv3IHXIjC2kXMbq0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;782&quot; height=&quot;115&quot; data-origin-width=&quot;782&quot; data-origin-height=&quot;115&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Nested query&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Nested query에 사용되는 함수는 Exists, all, unique, contains, not 등이 있다. 대표적으로 exists에 대해 알아보자. Exists 다음에 오는 select 문장의 실행 결과가 존재하는지 검사하는 함수로, 튜플이 하나라도 존재하면 참, 아니면 거짓을 반환한다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1774956523034&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT *
FROM Customer C
WHERE NOT EXISTS (SELECT *
	FROM PreviousRental P
    	WHERE C.accountId = P.accountId)&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;집합 연산자&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;집합 연산에는 합집합(Union), 차집합(Except), 교집합(Intersect)이 있다. 일반적인 집합 연산과 같은 작업을 수행한다.&lt;/p&gt;
&lt;pre id=&quot;code_1774956743199&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT *, 'Rental' as sourceTable
FROM Rental
UNION
SELECT *, 'PreviousRental' as sourceTable
from PreviousRental&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전 대여 정보와 현재 대여 정보를 모두 질의하는 명령문이다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;관계 대수를 이용한 정보조작&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발자가 작성하는 SQL은 매우 편하지만, 문법이 인간 중심적인 언어이기 때문에 이 질의가 본질적으로 어떤 연산을 하는지를 엄밀하게 설명하기는 애매했다. 다른 말로 표현하자면, 서로 다른 SQL 질의가 같은 동작을 수행하는 경우가 많았다. 따라서 데이터베이스 이론에서는 SQL을 대신하여 질의를 순수한 연산으로 표현하기 위한 방법으로 관계대수를 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;관계대수는 데이터베이스를 관계(Realation), A set of tuples로 보고, 거기에 대해 적용할 수 있는 기본적인 연산들을 정의했다.&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Selection : 행 고르기&lt;/li&gt;
&lt;li&gt;Projection : 열 고르기&lt;/li&gt;
&lt;li&gt;Union : 합집합&lt;/li&gt;
&lt;li&gt;Difference : 차집합&lt;/li&gt;
&lt;li&gt;Intersect : 교집합&lt;/li&gt;
&lt;li&gt;Join, Product : 연결하기&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 실제로 관계대수는 어디서 쓰이는가를 알아보기 전에 우리가 작성한 SQL문이 Output을 산출하기까지 어던 과정을 거치는지 알아봐야 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;715&quot; data-origin-height=&quot;401&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Gzjph/dJMcahYbFDm/c0McmytoHtwqXveOg7MOt1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Gzjph/dJMcahYbFDm/c0McmytoHtwqXveOg7MOt1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Gzjph/dJMcahYbFDm/c0McmytoHtwqXveOg7MOt1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGzjph%2FdJMcahYbFDm%2Fc0McmytoHtwqXveOg7MOt1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;715&quot; height=&quot;401&quot; data-origin-width=&quot;715&quot; data-origin-height=&quot;401&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로그래밍언어개론, 컴파일러개론을 수강했다면, 그 과정이 비슷하다는 것을 느낄 것이다. 나는 일단 처음이라 낯설긴 하다... 아무튼 SQL문이 입력되면, 이 SQL문을 컴퓨터가 관계대수로 나타내고 명령어의 순서를 최적화한다. 이후 순서에 맞춰 실행을 하게 되고 Output이 나온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최적화 과정에 대해 알아보자. DBMS는 Selection, Projection과 같은 관계 대수 연산자들의 조합으로 구성된 관계 대수 연산을 구현한 여러개의 알고리즘 가지고 있다. 이러한 DBMS에 의해 구현되는 최적화 모듈은 특정 질의와 특정 데이터베이스 설계에 적용되는 실행 전략들을 고려하여 질의의 순서를 최적화한다. 말은 어렵지만... 간단하게 DBMS가 관계 대수 연산 알고리즘을 여러개 가지고 있고, 이 DBMS에 의해 구현된 최적화 모듈이 실제로 우리의 SQL 명령문을 최적화한다고 생각하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단한 최적화 예제를 하나 살펴보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;412&quot; data-origin-height=&quot;133&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ovXlQ/dJMcabKtyOS/1cbwnHMOLitQr4KHqGADkk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ovXlQ/dJMcabKtyOS/1cbwnHMOLitQr4KHqGADkk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ovXlQ/dJMcabKtyOS/1cbwnHMOLitQr4KHqGADkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FovXlQ%2FdJMcabKtyOS%2F1cbwnHMOLitQr4KHqGADkk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;412&quot; height=&quot;133&quot; data-origin-width=&quot;412&quot; data-origin-height=&quot;133&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같은 명령어는 관계대수 형태로 변경되고, 이를 트리 형태로 나타낸다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;456&quot; data-origin-height=&quot;322&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Nn9pC/dJMcabjoOzU/OOkqqtNK5mc3dLjmNh8toK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Nn9pC/dJMcabjoOzU/OOkqqtNK5mc3dLjmNh8toK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Nn9pC/dJMcabjoOzU/OOkqqtNK5mc3dLjmNh8toK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNn9pC%2FdJMcabjoOzU%2FOOkqqtNK5mc3dLjmNh8toK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;456&quot; height=&quot;322&quot; data-origin-width=&quot;456&quot; data-origin-height=&quot;322&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후, 질의 순서를 최적화하고, 실행을 위한 계획을 세운다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;820&quot; data-origin-height=&quot;356&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GYmx2/dJMcaaY3xrV/dMNfUWbfja7MpkxsKfM0nK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GYmx2/dJMcaaY3xrV/dMNfUWbfja7MpkxsKfM0nK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GYmx2/dJMcaaY3xrV/dMNfUWbfja7MpkxsKfM0nK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGYmx2%2FdJMcaaY3xrV%2FdMNfUWbfja7MpkxsKfM0nK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;820&quot; height=&quot;356&quot; data-origin-width=&quot;820&quot; data-origin-height=&quot;356&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;564&quot; data-origin-height=&quot;94&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Q5Y3d/dJMcagkFhww/0eyMW5KUS8cw10OAhgUkKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Q5Y3d/dJMcagkFhww/0eyMW5KUS8cw10OAhgUkKK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Q5Y3d/dJMcagkFhww/0eyMW5KUS8cw10OAhgUkKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQ5Y3d%2FdJMcagkFhww%2F0eyMW5KUS8cw10OAhgUkKK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;564&quot; height=&quot;94&quot; data-origin-width=&quot;564&quot; data-origin-height=&quot;94&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;각 관계대수 연산자 별 생김새&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 Select는 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;480&quot; data-origin-height=&quot;62&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YAvTj/dJMcagLLKan/iOZ9wQSrWvWKiUYQcQx7a1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YAvTj/dJMcagLLKan/iOZ9wQSrWvWKiUYQcQx7a1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YAvTj/dJMcagLLKan/iOZ9wQSrWvWKiUYQcQx7a1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYAvTj%2FdJMcagLLKan%2FiOZ9wQSrWvWKiUYQcQx7a1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;480&quot; height=&quot;62&quot; data-origin-width=&quot;480&quot; data-origin-height=&quot;62&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;706&quot; data-origin-height=&quot;68&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bgbmCG/dJMcag53KwQ/mIwjkgBHgkWPFokFdYBHGk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bgbmCG/dJMcag53KwQ/mIwjkgBHgkWPFokFdYBHGk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bgbmCG/dJMcag53KwQ/mIwjkgBHgkWPFokFdYBHGk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbgbmCG%2FdJMcag53KwQ%2FmIwjkgBHgkWPFokFdYBHGk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;706&quot; height=&quot;68&quot; data-origin-width=&quot;706&quot; data-origin-height=&quot;68&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Projection은 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;414&quot; data-origin-height=&quot;89&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QR0aU/dJMcaaSj7y6/E61jNk33ancY3PGPSJKZlk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QR0aU/dJMcaaSj7y6/E61jNk33ancY3PGPSJKZlk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QR0aU/dJMcaaSj7y6/E61jNk33ancY3PGPSJKZlk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQR0aU%2FdJMcaaSj7y6%2FE61jNk33ancY3PGPSJKZlk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;414&quot; height=&quot;89&quot; data-origin-width=&quot;414&quot; data-origin-height=&quot;89&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고로 projection의 결과는 집합이므로, 모든 중복은 제거된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;합집합, 교집합, 차집합은 우리가 흔히 잘 아는 기호를 그대로 사용한다. 여기서 집합 연산자는 연산을 수행하려는 두 릴레이션이 같은 형태(Union-Compatible)를 지니고 있을 때 적용이 가능하다. 즉, 두 릴레이션이 가지고 있는 attribute의 개수(degree)가 같고, 대응하는 attribute 별로 타입(domain)이 동일해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 Product이다. 카티션 프로덕트(Catesian Product)라고 부르며, 두 릴레이션을 가지고 새로운 릴레이션을 생성한다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;179&quot; data-origin-height=&quot;26&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/doW45c/dJMcaax0OxS/yT27q2iBMM2gnaXhnUz10k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/doW45c/dJMcaax0OxS/yT27q2iBMM2gnaXhnUz10k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/doW45c/dJMcaax0OxS/yT27q2iBMM2gnaXhnUz10k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdoW45c%2FdJMcaax0OxS%2FyT27q2iBMM2gnaXhnUz10k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;179&quot; height=&quot;26&quot; data-origin-width=&quot;179&quot; data-origin-height=&quot;26&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나, 이렇게 생성한 relation은 문제가 많다. Employee의 tuple이 3개, TimeCard의 tuple이 4개라고 가정하면, 3 x 4 = 12, 총 12개의 tuple이 만들어진다. 여기서 문제는, 공유하고 있는 PK - FK가 없기 때문에, 적절한 조건 없이 카티션 프로덕트를 진행하게 되면 이 12개의 tuple 중 전혀 관계없는 attribute들이 하나의 tuple로 구성되어 있는 케이스가 있다는 것이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 조건을 걸어 Join연산을 진행해야 한다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;433&quot; data-origin-height=&quot;73&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/B5Yhk/dJMcahqmOpG/pqRS0Avf4kT0kKVELhlDw1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/B5Yhk/dJMcahqmOpG/pqRS0Avf4kT0kKVELhlDw1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/B5Yhk/dJMcahqmOpG/pqRS0Avf4kT0kKVELhlDw1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FB5Yhk%2FdJMcahqmOpG%2FpqRS0Avf4kT0kKVELhlDw1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;433&quot; height=&quot;73&quot; data-origin-width=&quot;433&quot; data-origin-height=&quot;73&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Join의 경우, Selection과 Cartesian Product 2개의 관계 대수 연산자로 표현된다. 이를 좀 더 간단하게 나타내기 위한 연산자가 자연조인(Natural Join)이다. 자연조인은 같은 이름의 attribute를 자동으로 기준 삼아 join하고, 중복 컬럼도 하나로 합쳐주는 join이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;282&quot; data-origin-height=&quot;34&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qwmE2/dJMcaiQh3QE/phelksBUeKZt3lOz2Yd9Tk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qwmE2/dJMcaiQh3QE/phelksBUeKZt3lOz2Yd9Tk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qwmE2/dJMcaiQh3QE/phelksBUeKZt3lOz2Yd9Tk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqwmE2%2FdJMcaiQh3QE%2FphelksBUeKZt3lOz2Yd9Tk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;282&quot; height=&quot;34&quot; data-origin-width=&quot;282&quot; data-origin-height=&quot;34&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;771&quot; data-origin-height=&quot;203&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kGl2X/dJMcaiJwBH0/LKLBbnnKBxFvPEC0ldJckK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kGl2X/dJMcaiJwBH0/LKLBbnnKBxFvPEC0ldJckK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kGl2X/dJMcaiJwBH0/LKLBbnnKBxFvPEC0ldJckK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkGl2X%2FdJMcaiJwBH0%2FLKLBbnnKBxFvPEC0ldJckK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;771&quot; height=&quot;203&quot; data-origin-width=&quot;771&quot; data-origin-height=&quot;203&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 자연조인은 같은 이름의 attribute는 중복을 제거하여 하나로 합치게 되는데, 이와는 반대로 중복되는 attribute들을 모두 살려 join하는 방식이 동등조인(Equi-Join)이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;406&quot; data-origin-height=&quot;33&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cyNRrQ/dJMcabRcgxr/0kA2tGAHPMkSoqUkIYWhp1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cyNRrQ/dJMcabRcgxr/0kA2tGAHPMkSoqUkIYWhp1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cyNRrQ/dJMcabRcgxr/0kA2tGAHPMkSoqUkIYWhp1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcyNRrQ%2FdJMcabRcgxr%2F0kA2tGAHPMkSoqUkIYWhp1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;406&quot; height=&quot;33&quot; data-origin-width=&quot;406&quot; data-origin-height=&quot;33&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;809&quot; data-origin-height=&quot;181&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c2L1Gb/dJMcaiCMkUN/GmruQqTBLJLisRU4iMg820/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c2L1Gb/dJMcaiCMkUN/GmruQqTBLJLisRU4iMg820/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c2L1Gb/dJMcaiCMkUN/GmruQqTBLJLisRU4iMg820/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc2L1Gb%2FdJMcaiCMkUN%2FGmruQqTBLJLisRU4iMg820%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;809&quot; height=&quot;181&quot; data-origin-width=&quot;809&quot; data-origin-height=&quot;181&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 외에 부가적인 관계 연산자로 집단화 연산의 Average, Count 등이 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;278&quot; data-origin-height=&quot;54&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bEsaST/dJMcaaSj7V5/J6NN5rstrV6nrkTraornaK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bEsaST/dJMcaaSj7V5/J6NN5rstrV6nrkTraornaK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bEsaST/dJMcaaSj7V5/J6NN5rstrV6nrkTraornaK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbEsaST%2FdJMcaaSj7V5%2FJ6NN5rstrV6nrkTraornaK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;278&quot; height=&quot;54&quot; data-origin-width=&quot;278&quot; data-origin-height=&quot;54&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>CS/데이터베이스</category>
      <author>PiLove</author>
      <guid isPermaLink="true">https://pi-love0314.tistory.com/48</guid>
      <comments>https://pi-love0314.tistory.com/entry/%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4-Week5-%EC%9D%B4%EB%A1%A0-SQL-2#entry48comment</comments>
      <pubDate>Tue, 31 Mar 2026 21:08:20 +0900</pubDate>
    </item>
    <item>
      <title>[영상처리] Week4. Image filtering</title>
      <link>https://pi-love0314.tistory.com/entry/%EC%98%81%EC%83%81%EC%B2%98%EB%A6%AC-Week4-%EC%9D%B4%EB%A1%A0-Image-filtering</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;충남대학교 고영준 교수님, 영상처리 4주차 강의 정리입니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Image filtering&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지난 시간에 배웠던 point processing은 하나의 pixel이 output의 하나의 pixel에 1대1로 대응한 반면, image filtering에서는 특정 크기의 filter를 input image의 각 pixel에 대하여 filter의 크기만큼 주변 이웃 pixel들에 대한 연산을 통해 pixel값을 구하게 된다. 말로 표현하자니... 좀 헷갈리는데 그림으로 보면 이해하기 쉽다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;218&quot; data-origin-height=&quot;233&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cHKGlA/dJMcadnUf4G/ifLjtDC7nSrznT4KSInfTk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cHKGlA/dJMcadnUf4G/ifLjtDC7nSrznT4KSInfTk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cHKGlA/dJMcadnUf4G/ifLjtDC7nSrznT4KSInfTk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcHKGlA%2FdJMcadnUf4G%2FifLjtDC7nSrznT4KSInfTk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;184&quot; height=&quot;197&quot; data-origin-width=&quot;218&quot; data-origin-height=&quot;233&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 다음과 같이 3 by 3 filter를 가정하자. 참고로 이 그림과 같이 filter의 각 자리에 대한 가중치, 즉 filter 내부의 모든 값들이 서로 같고, 그 전체의 합이 1이 되는 filter를 average filter라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;745&quot; data-origin-height=&quot;562&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cc9byY/dJMcaf0k3BR/RaLA34eUNj5z5juvESCXf0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cc9byY/dJMcaf0k3BR/RaLA34eUNj5z5juvESCXf0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cc9byY/dJMcaf0k3BR/RaLA34eUNj5z5juvESCXf0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcc9byY%2FdJMcaf0k3BR%2FRaLA34eUNj5z5juvESCXf0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;745&quot; height=&quot;562&quot; data-origin-width=&quot;745&quot; data-origin-height=&quot;562&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 pixel에 대하여 위 그림과 같이 연산을 진행하게 된다. 우선 해당 자리의 pixel은 주변 이웃 pixel들까지 모두 0이기 때문에 그 결과도 0이 되게 된다. filter를 오른쪽으로 한칸 움직여서 적용해보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;726&quot; data-origin-height=&quot;566&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mAGfh/dJMcaiitsZn/60PPy2gBditejuXHgLmIW1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mAGfh/dJMcaiitsZn/60PPy2gBditejuXHgLmIW1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mAGfh/dJMcaiitsZn/60PPy2gBditejuXHgLmIW1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmAGfh%2FdJMcaiitsZn%2F60PPy2gBditejuXHgLmIW1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;726&quot; height=&quot;566&quot; data-origin-width=&quot;726&quot; data-origin-height=&quot;566&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연산은 Input image의 3 by 3 matrix와 3 by 3 filter의 동일한 자리끼리 곱셈을 진행하고 그 값을 모두 더하는 방식으로 진행된다. 따라서 (0 x 1/9) + (0 x 1/9) + (0 x 1/9) + (0 x 1/9) + (0 x 1/9) + (0 x 1/9) + (0 x 1/9) + (0 x 1/9) + (90 x 1/9) = 10이 된다. 이런 식으로 input image의 모든 pixel에 대해 연산을 진행하게 된다. 가장자리의 pixel에 대한 연산은 뒤에서 설명하도록 하겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어쨋든 이러한 연산을 통해 얻을 수 있는 효과는 무엇일까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 pixel이 주변 pixel 값을 참고하여 평균을 낸 값으로 변경되기 때문에, pixel 사이의 contrast가 줄어들 것이다. 이러한 효과를 smoothing이라고 한다. 실제 이미지는 아래와 같이 변경된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;741&quot; data-origin-height=&quot;245&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/boVg1Q/dJMcaa5PmbW/YqZTT0CCXzgKf1iCJ0wLNk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/boVg1Q/dJMcaa5PmbW/YqZTT0CCXzgKf1iCJ0wLNk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/boVg1Q/dJMcaa5PmbW/YqZTT0CCXzgKf1iCJ0wLNk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FboVg1Q%2FdJMcaa5PmbW%2FYqZTT0CCXzgKf1iCJ0wLNk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;741&quot; height=&quot;245&quot; data-origin-width=&quot;741&quot; data-origin-height=&quot;245&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;음... 재밌당&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번엔 filter의 종류를 변경해보자. 다음과 같은 filter가 있다고 가정하자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;309&quot; data-origin-height=&quot;105&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lIsOy/dJMcagdUFgB/cTGM2tbTdkI2rX4mYrUntk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lIsOy/dJMcagdUFgB/cTGM2tbTdkI2rX4mYrUntk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lIsOy/dJMcagdUFgB/cTGM2tbTdkI2rX4mYrUntk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlIsOy%2FdJMcagdUFgB%2FcTGM2tbTdkI2rX4mYrUntk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;309&quot; height=&quot;105&quot; data-origin-width=&quot;309&quot; data-origin-height=&quot;105&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 filter는 sharpening filter라고 부른다. 우선 해당 해당 filter에 대해 이해하기 위해 직관적으로 다음과 같이 표현할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;출력 pixel 값 = (2 x 중심 pixel) - (주변 pixel 3x3 평균)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Input pixel에 대해여 Output pixel이 어떤 의미를 가질까? 중심 pixel의 밝기를 2배를 올리고, 주변의 평균으로 빼준다. 이는 곧, 중심 pixel과 주변 pixel 평균과 얼마나 다른지를 의미한다. 만약 주변 pixel의 크기가 거의 비슷한 곳은 중심 pixel의 연산 결과가 비슷하게 유지되겠지만, 주변 pixel의 크기가 서로 큰 차이가 난다면 연산 결과도 더 크게 차이가 날 것이다. 따라서 이미지에서 밝기가 급격히 변하는 부분, 즉 경계, 윤곽 등에서 선명함이 살아나는 효과를 준다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;573&quot; data-origin-height=&quot;309&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/opeqM/dJMcafMRdEU/34AgFn7kaxufMPcRVwf8Ok/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/opeqM/dJMcafMRdEU/34AgFn7kaxufMPcRVwf8Ok/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/opeqM/dJMcafMRdEU/34AgFn7kaxufMPcRVwf8Ok/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FopeqM%2FdJMcafMRdEU%2F34AgFn7kaxufMPcRVwf8Ok%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;573&quot; height=&quot;309&quot; data-origin-width=&quot;573&quot; data-origin-height=&quot;309&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;음... 역시나 재밌당&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또 다른 filter로 이런 것도 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;764&quot; data-origin-height=&quot;460&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/G3GRG/dJMcaaxZTDJ/gw7893lfqjC3uzqhdGrXh0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/G3GRG/dJMcaaxZTDJ/gw7893lfqjC3uzqhdGrXh0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/G3GRG/dJMcaaxZTDJ/gw7893lfqjC3uzqhdGrXh0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FG3GRG%2FdJMcaaxZTDJ%2Fgw7893lfqjC3uzqhdGrXh0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;764&quot; height=&quot;460&quot; data-origin-width=&quot;764&quot; data-origin-height=&quot;460&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Filter의 모양을 보니, 각 pixel에 대하여 해당 pixel을 왼쪽으로는 양의 가중치를 곱해주고, 해당 pixel을 오른쪽으로는 음의 가중치를 곱해준다. 만약 input image의 3 by 3 matrix에 대하여 9개의 pixel이 큰 차이가 없다면 결과는 0에 가까워서 어두워질 것이다. 반면에 3 by 3 matrix에 대하여 왼쪽과 오른쪽 세로로 그 값의 차이가 크다면 결과는 높은 값을 가지게 될 것이다. 즉, 세로 윤곽선에 대하여 집중하여 표현할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;764&quot; data-origin-height=&quot;456&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1hwmO/dJMcabDFux9/rwshgrpyFiR1Ds8AkBfCS0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1hwmO/dJMcabDFux9/rwshgrpyFiR1Ds8AkBfCS0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1hwmO/dJMcabDFux9/rwshgrpyFiR1Ds8AkBfCS0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1hwmO%2FdJMcabDFux9%2FrwshgrpyFiR1Ds8AkBfCS0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;764&quot; height=&quot;456&quot; data-origin-width=&quot;764&quot; data-origin-height=&quot;456&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가로 윤곽선에 대해서도 다음과 같은 filter를 통해 표현할 수 있다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Gaussian filters&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Gaussian filter는 average filter처럼 smoothing filter지만, 훨씬 더 자연스러운 smoothing을 가능하게 한다. 우선 식을 확인해보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;268&quot; data-origin-height=&quot;66&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WLDP3/dJMcafe1T31/nBcQvBBqMb5RZkXIxJKho1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WLDP3/dJMcafe1T31/nBcQvBBqMb5RZkXIxJKho1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WLDP3/dJMcafe1T31/nBcQvBBqMb5RZkXIxJKho1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWLDP3%2FdJMcafe1T31%2FnBcQvBBqMb5RZkXIxJKho1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;268&quot; height=&quot;66&quot; data-origin-width=&quot;268&quot; data-origin-height=&quot;66&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;... 식은 복잡하지만.. 그래프의 개형을 통해 우리가 어떤 filter를 사용할 것인지 확인할 수 있다. 그래프를 쉽게 그리기 위해서는 뮤를 없애고 (1/e)^(x^2) 에 대해서 그래프를 그리면 된다. x가 gaussian filter의 pixel값이라고 가정하고, x의 값이 0보다 커지면 점점 감소하게 되어 0에 수렴하게 된다. x의 값이 0보다 작아져도 점점 감소하게 되어 0에 수렴하게 된다. 그러면 우리가 흔히 잘 아는 0을 기준으로 대칭인 종모양 그래프가 그려지게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 시그마까지 고려해보자. 시그마가 식에 포함되면 (1/e)^((x^2)/시그마) 가 되고, 시그마 값이 1보다 크면 기존 x^2보다 감소 폭이 더 완만해질 것이다. 시그마가 1일 때와 시그마가 2일 때를 가정하고 x값을 임의로 2나 4 등으로 넣어 생각해보면 된다. 반대로 시그마 값이 0보다 크고 1보다 작을 경우, 기존 x^2보다 감소 폭이 더 가파라질 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 주저리 주저리 그래프를 상상하며 쓴 글은 1차원을 기준으로 쓴 것이다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;248&quot; data-origin-height=&quot;81&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yVo8X/dJMcaadHcLJ/8ksvKJi9vkTfWlVxoSaMlK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yVo8X/dJMcaadHcLJ/8ksvKJi9vkTfWlVxoSaMlK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yVo8X/dJMcaadHcLJ/8ksvKJi9vkTfWlVxoSaMlK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyVo8X%2FdJMcaadHcLJ%2F8ksvKJi9vkTfWlVxoSaMlK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;248&quot; height=&quot;81&quot; data-origin-width=&quot;248&quot; data-origin-height=&quot;81&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2차원 데이터에 대한 식은 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;871&quot; data-origin-height=&quot;205&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dSpSz6/dJMcabcy8UM/MOeu4TC8pyj81q7DxkY1I0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dSpSz6/dJMcabcy8UM/MOeu4TC8pyj81q7DxkY1I0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dSpSz6/dJMcabcy8UM/MOeu4TC8pyj81q7DxkY1I0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdSpSz6%2FdJMcabcy8UM%2FMOeu4TC8pyj81q7DxkY1I0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;871&quot; height=&quot;205&quot; data-origin-width=&quot;871&quot; data-origin-height=&quot;205&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2차원 식에 대한 그래프는 위와 같고, 시그마 값에 따라 그래프의 개형이 달라지는 것은 동일하다. 이걸 filter로 사용한다고 하면, 중심에 좀 더 높은 가중치를 두고, 중심에서 멀어질 수록 가중치가 줄어든다는 것을 확인할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;340&quot; data-origin-height=&quot;211&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cyIBZ3/dJMcajaAbvE/GO1Sgi2lsZAqgKt5iRkk00/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cyIBZ3/dJMcajaAbvE/GO1Sgi2lsZAqgKt5iRkk00/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cyIBZ3/dJMcajaAbvE/GO1Sgi2lsZAqgKt5iRkk00/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcyIBZ3%2FdJMcajaAbvE%2FGO1Sgi2lsZAqgKt5iRkk00%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;340&quot; height=&quot;211&quot; data-origin-width=&quot;340&quot; data-origin-height=&quot;211&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Filter의 각 자리에 대한 계산은 식에 자리에 해당하는 x, y값을 대입해주면 된다. 그리고 그 값들을 모두 더하여 나눠주면 gaussian filter가 완성된다. 위 그림에는 나눠주지 않았는데, 나눠주어야 한다. 나눠주어야만 input image의 전체적인 밝기를 유지할 수 있다. 어쨋든 이걸 직접 적용하면 다음과 같아진다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;581&quot; data-origin-height=&quot;336&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HFtGb/dJMcafF4n0P/aNSb5AKhUOsDTK5FsGxV3k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HFtGb/dJMcafF4n0P/aNSb5AKhUOsDTK5FsGxV3k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HFtGb/dJMcafF4n0P/aNSb5AKhUOsDTK5FsGxV3k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHFtGb%2FdJMcafF4n0P%2FaNSb5AKhUOsDTK5FsGxV3k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;581&quot; height=&quot;336&quot; data-origin-width=&quot;581&quot; data-origin-height=&quot;336&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적인 box filter에 비해 더 자연스럽게 smoothing 처리 해주는 것을 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Gaussian filter의 크기는 보통 다음과 같은 사항을 고려하여 정한다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;filter 원소의 합이 1&lt;/li&gt;
&lt;li&gt;filter 가장자리의 값이 0에 가까워지게&lt;/li&gt;
&lt;li&gt;Rule of thumb for Gaussian : filter의 너비의 절반을 대략 3x시그마 정도로 잡는다&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3번의 이유도 그래프를 생각해보면 왜 그런지 알 수 있다. 일단 두번째 사항으로 filter의 가장자리의 값은 0에 가까워져야 한다. 만약 시그마의 값이 크다면, 그래프의 모양도 넓게 펴질 것이다. 여기서 filter의 크기를 작게 잡는다면, filter의 가장자리 0에 가까워지지 않을 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;436&quot; data-origin-height=&quot;206&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vTUFx/dJMb99TmZdu/kduvvnFkFSBfqMuMzquop1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vTUFx/dJMb99TmZdu/kduvvnFkFSBfqMuMzquop1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vTUFx/dJMb99TmZdu/kduvvnFkFSBfqMuMzquop1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvTUFx%2FdJMb99TmZdu%2FkduvvnFkFSBfqMuMzquop1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;436&quot; height=&quot;206&quot; data-origin-width=&quot;436&quot; data-origin-height=&quot;206&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 그래프처럼 시그마 값이 크다고 가정하자. 그러면 입력 pixel x의 위치가 중심으로부터 멀리 떨어져야만 0에 가까운 값을 가지게 된다. 따라서 filter의 크기가 커야 중심으로부터 더 멀리 떨어진 x까지 연산이 가능하다. 따라서 시그마의 값이 크면 filter의 값도 커져야 하고, 그 비율이 대충 Rule of thumb for Gaussian에서 제시한 정도가 되는 것이다. 참고로 빨간색 파란색 세로 선은 filter 크기에 따른 입력 pixel x의 위치를 표현하기 위해 그린거다... 반듯하지 않네..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Separability of the Gaussian filter&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Gaussian filter는 이미지 처리에 대해서 입력 값으로 2개를 받게 된다. 이를 분리하여 게산할 수도 있는데, 식으로 표현하면 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;730&quot; data-origin-height=&quot;279&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c6UoGZ/dJMcajhlygJ/D3Y6QH1cpLTpT0gYonYGb0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c6UoGZ/dJMcajhlygJ/D3Y6QH1cpLTpT0gYonYGb0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c6UoGZ/dJMcajhlygJ/D3Y6QH1cpLTpT0gYonYGb0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc6UoGZ%2FdJMcajhlygJ%2FD3Y6QH1cpLTpT0gYonYGb0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;730&quot; height=&quot;279&quot; data-origin-width=&quot;730&quot; data-origin-height=&quot;279&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;식으로는 분리가 되는 것을 확인했다. 실제 matrix에서 어떻게 나뉘는지 확인해보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;696&quot; data-origin-height=&quot;523&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OttCe/dJMcaivY4hl/Q9w4fHGfRRecF1OvRX4Dqk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OttCe/dJMcaivY4hl/Q9w4fHGfRRecF1OvRX4Dqk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OttCe/dJMcaivY4hl/Q9w4fHGfRRecF1OvRX4Dqk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOttCe%2FdJMcaivY4hl%2FQ9w4fHGfRRecF1OvRX4Dqk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;696&quot; height=&quot;523&quot; data-origin-width=&quot;696&quot; data-origin-height=&quot;523&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예로 가져온 filter가 gaussian filter는 아니지만, gaussian filter처럼 filter의 중심을 기준으로 대칭인 filter이므로, 그 성격은 동일하다고 볼 수 있다. Filter의 중심을 기준으로 대칭이기 때문에 2D를 1D 벡터의 곱으로 분리할 수 있다. 그리고 row를 먼저 연산해주고 나온 결과값에, 그림에는 없지만 column까지 곱해주면 그 결과가 동일한 것을 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이에 대한 증명은 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;581&quot; data-origin-height=&quot;820&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcL2Hr/dJMcabRbnLt/1VNNGOu1kNASraa0De2K8k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcL2Hr/dJMcabRbnLt/1VNNGOu1kNASraa0De2K8k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcL2Hr/dJMcabRbnLt/1VNNGOu1kNASraa0De2K8k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbcL2Hr%2FdJMcabRbnLt%2F1VNNGOu1kNASraa0De2K8k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;581&quot; height=&quot;820&quot; data-origin-width=&quot;581&quot; data-origin-height=&quot;820&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>CS/영상처리</category>
      <author>PiLove</author>
      <guid isPermaLink="true">https://pi-love0314.tistory.com/47</guid>
      <comments>https://pi-love0314.tistory.com/entry/%EC%98%81%EC%83%81%EC%B2%98%EB%A6%AC-Week4-%EC%9D%B4%EB%A1%A0-Image-filtering#entry47comment</comments>
      <pubDate>Mon, 30 Mar 2026 23:43:19 +0900</pubDate>
    </item>
    <item>
      <title>[데이터통신] Week5-6. Physical layer</title>
      <link>https://pi-love0314.tistory.com/entry/%EB%8D%B0%EC%9D%B4%ED%84%B0%ED%86%B5%EC%8B%A0-Week5-6-%EC%9D%B4%EB%A1%A0-Physical-layer</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;충남대학교 김기일 교수님, 데이터통신 과목 5~6주차 수업 정리입니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Data and Signals&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Physical layer를 이해하기 위해선 가장 먼저 우리가 전달하고자 하는 data에 대해 이해해야 한다. Data는 우리가 보내고 싶은 정보 그 자체이다. 예를 들면, 텍스트, 오디오, 이미지 같은 것을 의미한다. 반면, signal은 그 data를 실제 매체를 통해 옮기기 위한 물리적 표현이다. 컴퓨터에서는 data가 bit로 표현되지만, 실제로 통신을 위해 선이나 공기 속에서는 전기 펄스나 빛의 형태로 전달된다. Physical layer는 바로 이 data에서 signal로의 변환과 전달을 담당한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;652&quot; data-origin-height=&quot;230&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJVpQd/dJMcabDFr6f/iDQWc86bgKNVkz3JyKdvnK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJVpQd/dJMcabDFr6f/iDQWc86bgKNVkz3JyKdvnK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJVpQd/dJMcabDFr6f/iDQWc86bgKNVkz3JyKdvnK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJVpQd%2FdJMcabDFr6f%2FiDQWc86bgKNVkz3JyKdvnK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;652&quot; height=&quot;230&quot; data-origin-width=&quot;652&quot; data-origin-height=&quot;230&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Week3 수업 시간에 배웠던 통신을 구성하는 5개의 요소가 기억나는가? 송신자, 수신자, 전달하고자 하는 메세지, 프로토콜, 그리고 전송 매체(transmission medium)이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전송은 위 그림처럼 송신자 측에서 data를 signal로 변환한 후 전송매체를 통해 전송하게 돼고, 수신자 측에서 signal을 data로 다시 변환하여 수신하게 된다. Data를 signal로 변환하는 과정을 encoding, signal을 data로 변환하는 과정을 decoding으로 이해하면 쉽다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 등장하는 문제가 바로, 컴퓨터는 0과 1로 동작하는 반면, 현실 세계는 Amplitude(진폭)와 Frequency(주파수) 같은 연속적인 물리량으로 움직인다는 것이다. 즉, physical layer의 가장 큰 과제는 digital 세계의 bit들을 analog 세계의 signal로 변환하는 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;426&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bTSRz5/dJMcadIcolV/YByfhcmxeMVgSNaWgcXy80/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bTSRz5/dJMcadIcolV/YByfhcmxeMVgSNaWgcXy80/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bTSRz5/dJMcadIcolV/YByfhcmxeMVgSNaWgcXy80/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbTSRz5%2FdJMcadIcolV%2FYByfhcmxeMVgSNaWgcXy80%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;773&quot; height=&quot;426&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;426&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 그림은 signal로부터 packet이 생성되기 까지의 과정을 단순화한 그림이다. Continuous한 analog signal을 Discrete한 digital signal로 변환되고 bit stream으로 표현된다. 이러한 bit들이 모여 packet을 생성하게 되고, 이러한 packet은 결국 상위 layer의 다양한 의미를 담은 data가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Data는 analog 또는 digital로 표현될 수 있으며, analog data는 continuous한 케이스를 의미하며, digital data은 discrete한 케이스를 의미한다. Signal도 마찬가지이다. Analog signal은 시간에 따라 무한한 값을 가질 수 있고, digital signal은 제한된 몇 개의 값만 가진다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;790&quot; data-origin-height=&quot;511&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/epF9On/dJMcai3NikZ/4h6hccLK9Uu07i7ysQwdo0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/epF9On/dJMcai3NikZ/4h6hccLK9Uu07i7ysQwdo0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/epF9On/dJMcai3NikZ/4h6hccLK9Uu07i7ysQwdo0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FepF9On%2FdJMcai3NikZ%2F4h6hccLK9Uu07i7ysQwdo0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;790&quot; height=&quot;511&quot; data-origin-width=&quot;790&quot; data-origin-height=&quot;511&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그림에서 확인할 수 있듯이 analog signal은 x축 값에 대응하는 y축 값이 무한하다. 애초에 0~1 사이의 실수가 매우 많이 존재하므로 analog signal의 형태가 반복적이더라도 x값에 대응하는 y값이 무한하다는 의미이다. 반면에, digital signal의 경우 x값에 대응하는 y값이 상수로 정해져있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 Signal은 periodic과 nonperiodic으로 나눌 수 있다. Periodic signal은 일정한 패턴을 한 주기(period)마다 반복하고, nonperiodic signal은 반복되는 패턴이 없다. 참고로 데이터통신에서는 보통 periodic analog signal과 nonperiodic digital signal을 사용한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Periodic Analog Signals&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바로 앞 목차에서 signal이 analog/digital, periodic/nonperiodic으로 나뉜다는 것을 확인했다. 이번 목차에서는 periodic analog signal에 대해서 다룰 예정이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Periodic analog signal은 simple과 composite으로 나눌 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;689&quot; data-origin-height=&quot;235&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pNMOA/dJMb996ULaY/t3CRvwKGpOyUZCVtywNit1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pNMOA/dJMb996ULaY/t3CRvwKGpOyUZCVtywNit1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pNMOA/dJMb996ULaY/t3CRvwKGpOyUZCVtywNit1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpNMOA%2FdJMb996ULaY%2Ft3CRvwKGpOyUZCVtywNit1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;689&quot; height=&quot;235&quot; data-origin-width=&quot;689&quot; data-origin-height=&quot;235&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Simple periodic analog signal의 대표가 바로 sine wave이다. Sine wave는 signal을 더 이상 쪼갤 수 없는 가장 기본적인 파형이다. 여기서 &quot;더 이상 쪼갤 수 없는&quot; 이라는 표현은 이후에 이해할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Sine wave를 이해할 때 핵심적인 속성은 크게 3가지 이다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;Amplitude(진폭)&lt;/b&gt;&lt;br /&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;788&quot; data-origin-height=&quot;517&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcqlRy/dJMb99TmWsB/NqBDRwOUpuCbTdRkoMLJok/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcqlRy/dJMb99TmWsB/NqBDRwOUpuCbTdRkoMLJok/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcqlRy/dJMb99TmWsB/NqBDRwOUpuCbTdRkoMLJok/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbcqlRy%2FdJMb99TmWsB%2FNqBDRwOUpuCbTdRkoMLJok%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;788&quot; height=&quot;517&quot; data-origin-width=&quot;788&quot; data-origin-height=&quot;517&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
Amplitude는 wave의 높이, 즉 얼마나 강한 signal인지를 나타낸다. Amplitude가 크다는 뜻은 해당 wave의 Peak 즉, 최대값이 크다는 의미이며, Amplitude가 클수록 signal의 세기가 더 크다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;b&gt;Frequency(주파수)&lt;br /&gt;&lt;/b&gt;&lt;/b&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;836&quot; data-origin-height=&quot;463&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b0T9BF/dJMcabcy61h/oxBtkzTFMKFtxMVJgYJQ9K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b0T9BF/dJMcabcy61h/oxBtkzTFMKFtxMVJgYJQ9K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b0T9BF/dJMcabcy61h/oxBtkzTFMKFtxMVJgYJQ9K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb0T9BF%2FdJMcabcy61h%2FoxBtkzTFMKFtxMVJgYJQ9K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;836&quot; height=&quot;463&quot; data-origin-width=&quot;836&quot; data-origin-height=&quot;463&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
Frequency란, 1초 동안 몇 번의 period가 반복되는지를 뜻한다. 위 그림에서 왼쪽 상단의 wave는 1초 동안 12번의 period가 관측되었으며 이를 12Hz라고 표현한다. 오른쪽 하단의 wave에서는 1초 동안 6번의 period가 관측되었으며 6Hz로 표현한다.&lt;br /&gt;&lt;br /&gt;집에서 사용하는 교류 전기는 60 Hz를 사용한다. 이에 대응하는 period는 약 16.6ms 이다. 이에 대한 계산 식은 다음과 같다.&lt;br /&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;556&quot; data-origin-height=&quot;57&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/did5CN/dJMcaiCLoHT/Rc87HIbklAerDT0XRo8hW1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/did5CN/dJMcaiCLoHT/Rc87HIbklAerDT0XRo8hW1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/did5CN/dJMcaiCLoHT/Rc87HIbklAerDT0XRo8hW1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdid5CN%2FdJMcaiCLoHT%2FRc87HIbklAerDT0XRo8hW1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;556&quot; height=&quot;57&quot; data-origin-width=&quot;556&quot; data-origin-height=&quot;57&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
즉, 당장 거실에 있는 등은 16.6ms의 속도로 꺼졌다 켜졌다를 반복하고 있는 것이다. 이거 배우고 좀 신기했다...&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;b&gt;Phase(위상)&lt;br /&gt;&lt;/b&gt;&lt;/b&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;760&quot; data-origin-height=&quot;520&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cJLzJn/dJMcaduD1cd/4IenlwIGCMZ8RkBTFxfDj0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cJLzJn/dJMcaduD1cd/4IenlwIGCMZ8RkBTFxfDj0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cJLzJn/dJMcaduD1cd/4IenlwIGCMZ8RkBTFxfDj0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcJLzJn%2FdJMcaduD1cd%2F4IenlwIGCMZ8RkBTFxfDj0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;760&quot; height=&quot;520&quot; data-origin-width=&quot;760&quot; data-origin-height=&quot;520&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
Phase는 wave가 시간축의 어느 지점에서 시작하는지를 의미한다. 위 그림에서 세 wave는 모두 서로 다른 phase를 가지고 있다. Time 0에 대한 phase는 위에서부터 차례대로 0도, 90도, 180도이다. 즉, 같은 Amplitude와 같은 Frequency를 가진 wave라고 해도 시작 위치가 다르면 서로 다른 phase를 가지게 된다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지금까지 sine wave를 통해 simple periodic analog signal에 대해 알아보았다. 그러나, 데이터통신에서는 이러한 simple periodic analog signal로는 충분하지 않다. 실제 data는 훨씬 복잡한 정보를 담아야 하므로 여러 simple periodic analog singal이 합쳐진 composite signal이 필요하다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;663&quot; data-origin-height=&quot;301&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EBw8g/dJMcafMRbPU/1ge2Xmoh6M5tktWDADGVG0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EBw8g/dJMcafMRbPU/1ge2Xmoh6M5tktWDADGVG0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EBw8g/dJMcafMRbPU/1ge2Xmoh6M5tktWDADGVG0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEBw8g%2FdJMcafMRbPU%2F1ge2Xmoh6M5tktWDADGVG0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;663&quot; height=&quot;301&quot; data-origin-width=&quot;663&quot; data-origin-height=&quot;301&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Composite signal은 서로 다른 amplitude, frequency, phase를 가진 여러 sine wave의 조합이며, periodic일 수도 있으며 nonperiodic일 수도 있다. 그림처럼 파랑색, 검은색, 빨간색의 simple sine wave가 모여서 하나의 composite signal을 구성하는 걸 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 여기서 각각의 simple sine wave는 서로 다른 frequency를 가지는데, 이 중 최대값과 최소값의 차이가 Bandwidth(대역폭)가 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;743&quot; data-origin-height=&quot;481&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BzooW/dJMcacJrQIy/KnhLeLdf5D9aal1zIjypGK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BzooW/dJMcacJrQIy/KnhLeLdf5D9aal1zIjypGK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BzooW/dJMcacJrQIy/KnhLeLdf5D9aal1zIjypGK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBzooW%2FdJMcacJrQIy%2FKnhLeLdf5D9aal1zIjypGK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;743&quot; height=&quot;481&quot; data-origin-width=&quot;743&quot; data-origin-height=&quot;481&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그림을 예시로... 위쪽 그림은, composite periodic signal을 구성하는 각각의 simple signal들이 1000~5000의 Frequency를 가지고, 최대값과 최소값의 차인 4000이 Bandwidth가 되는 것을 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 아래 그림은, composite nonperiodic signal을 구성하는 simple sinal들이 peridoci signal과 다르게 딱딱 떨어지지 않고 연속적인 범위로 퍼질 수 있음을 보여준다. 그래도 Frequency의 최대 최소의 차인 4000이 Bandwidth가 되는 것은 여전하다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Digital Signals&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Data는 analog signal로도 표현할 수 있지만, digital signal로도 표현될 수 있다. 예를 들어, 1은 높은 전압, 0은 0 전압으로 인코딩 수 있다. 또한 이러한 2개의 level만 사용하는 게 아닌 여러개의 level로도 표현할 수 있다. 아래 예시를 보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;795&quot; data-origin-height=&quot;315&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Nzjf1/dJMcajuZjH3/6sal78KKej8u8R2x5GDZXK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Nzjf1/dJMcajuZjH3/6sal78KKej8u8R2x5GDZXK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Nzjf1/dJMcajuZjH3/6sal78KKej8u8R2x5GDZXK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNzjf1%2FdJMcajuZjH3%2F6sal78KKej8u8R2x5GDZXK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;795&quot; height=&quot;315&quot; data-origin-width=&quot;795&quot; data-origin-height=&quot;315&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 왼쪽 그림부터 보면, signal이 2개의 level로 구성되어 있다. 또한 1초에 8개의 비트를 보내기 때문에 8bps로 표현할 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면 오른쪽 그림을 보면, signal이 4개의 level로 구성되어 있다. 각각의 4개의 level을 모두 표현하기 위해 사용하는 bit 수가 2로 늘어났다. 따라서 1초에 보내는 bit의 수도 16bps가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전송속도 측면에서 보면 오른쪽 그림이 더 빠르지만, 디코딩 측면에서의 난이도를 생각하면 왼쪽의 경우가 더 쉽다. 따라서 여러 고려사항을 생각하여 적절한 선택을 하는 것이 중요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Fourier analysis에 의하면 digital sinal은 곧 composite analog signal이다. 정확하게 어떤 의미인지는 설명해주시지 않았지만, 수학적으로 보면 digital sinal도 여러개의 sine wave를 합쳐서 만들 수 있기에 digital signal = composite analog signal로 해석할 수 있다고 한다. 그림을 보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;737&quot; data-origin-height=&quot;351&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bTEDDm/dJMcadO2t6Z/vNFJ0On6uK3sU90KH7bbik/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bTEDDm/dJMcadO2t6Z/vNFJ0On6uK3sU90KH7bbik/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bTEDDm/dJMcadO2t6Z/vNFJ0On6uK3sU90KH7bbik/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbTEDDm%2FdJMcadO2t6Z%2FvNFJ0On6uK3sU90KH7bbik%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;737&quot; height=&quot;351&quot; data-origin-width=&quot;737&quot; data-origin-height=&quot;351&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왼쪽 상단의 그래프는 digital signal이다. 그리고 오른쪽 상단을 보면 이 signal이 Frequency영역에서 여러 개의 Fequency 성분으로 나타나는 것을 확인할 수 있다. 즉, 왼쪽 상단의 digital signal은 여러 sine wave들이 합쳐져서 만들어졌다는 뜻이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, 오른쪽 그림을 보면 Frequency 영역에 대하여 &quot;...&quot;으로 표현한 걸 확인할 수 있다. 이는, digital signal의 모서리가 수직에 가깝게 갑자기 변하는 변화를 표현하기 위해 무한히 높은 Frequency 성분이 필요하기 때문이다. 그냥 단순하고 직관적으로 수직으로 변하는 변화량은 Frequency가 무한대에 가까워져야 표현이 가능하다고 생각하면 될 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Digital data를 channel에 보낼 때, 그냥 보낼 수도 있고, analog로 변환하여 보낼 수도 있다. 그러나 실제 transmission medium은 아무 signal이나 다 받아주는 게 아니다. 어떤 channel은 digital signal 그대로 보낼 수도 있고, 어떤 채널은 특정 주파수 대역의 analog signal만 잘 통과시킨다. 따라서 channel 종류에 따라 전송 방식이 달라진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Digital signal을 보내는 방법은 크게 2가지이다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Baseband transmission&lt;br /&gt;Digital signal을 그대로 보내는 방식이다. Bandwidth가 0부터 시작하는 channel에서 가능하다. 즉, 아주 낮은 주파수 성분부터 통과시킬 수 있는 channel이어야 한다.&lt;/li&gt;
&lt;li&gt;Broadband transmission&lt;br /&gt;Digital signal을 analog signal로 변환하여 보내는 방식이다. Bandwidth가 0부터 시작하지 않는 channel 즉, Bandpass channel에서 필요하다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Broadband transmission에서는 digital signal을 channel에서 허용하는 Bandwidth 안으로 옮겨서 보내야 한다. 이 과정을 Modulation(변조)라고 한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Transmission Impairment&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Signal이 transmission medium을 통해 전달될 때, 이 signal의 모양이 변화하게 된다. 이러한 손상을 Transmission Impairment라고 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;729&quot; data-origin-height=&quot;251&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tZOws/dJMcaa5U44I/DLLLGNNhACMCDsqW8ML811/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tZOws/dJMcaa5U44I/DLLLGNNhACMCDsqW8ML811/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tZOws/dJMcaa5U44I/DLLLGNNhACMCDsqW8ML811/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtZOws%2FdJMcaa5U44I%2FDLLLGNNhACMCDsqW8ML811%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;729&quot; height=&quot;251&quot; data-origin-width=&quot;729&quot; data-origin-height=&quot;251&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;Impairment의 종류에는 크게 3가지가 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;먼저 감쇄(Attenuation)에 대해 알아보자.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;677&quot; data-origin-height=&quot;323&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NzCjI/dJMcaiplBDA/kxnuvPsZRFxBnAiN07Zay1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NzCjI/dJMcaiplBDA/kxnuvPsZRFxBnAiN07Zay1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NzCjI/dJMcaiplBDA/kxnuvPsZRFxBnAiN07Zay1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNzCjI%2FdJMcaiplBDA%2FkxnuvPsZRFxBnAiN07Zay1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;677&quot; height=&quot;323&quot; data-origin-width=&quot;677&quot; data-origin-height=&quot;323&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Signal이 medium을 통해 전달되는 과정에서 medium의 저항에 의해 에너지를 잃게 되곤 한다. 이러한 에너지를 잃는 현상을 두고 감쇄라고 하며, 이를 해결하기 위해선 Amplifier를 두어서 감쇄된 에너지를 증폭하여 원본 signal의 에너지를 복원해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 Dsitortion에 대해 알아보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;727&quot; data-origin-height=&quot;373&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/INNoB/dJMcagZlghZ/FIqm3VSxoaoL6Oiw8ZNPo0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/INNoB/dJMcagZlghZ/FIqm3VSxoaoL6Oiw8ZNPo0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/INNoB/dJMcagZlghZ/FIqm3VSxoaoL6Oiw8ZNPo0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FINNoB%2FdJMcagZlghZ%2FFIqm3VSxoaoL6Oiw8ZNPo0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;727&quot; height=&quot;373&quot; data-origin-width=&quot;727&quot; data-origin-height=&quot;373&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Distortion은 composite signal에서 발생하는 현상이다. Composite signal은 전송될 때 각각의 bandwidth에 해당하는 simple signal로 분리되어 전송되는데, 각각 서로 다른 propagation speed를 가지고 있기 때문에, phase가 달라질 수 있다. 이로인해 출발과 도착 지점에서의 signal의 모양이 변화하는 현상이 발생한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 Noise에 대해 알아보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;754&quot; data-origin-height=&quot;296&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c6Q9D0/dJMcaflQW14/imIYiEhovYRgYiYoc2vj7k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c6Q9D0/dJMcaflQW14/imIYiEhovYRgYiYoc2vj7k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c6Q9D0/dJMcaflQW14/imIYiEhovYRgYiYoc2vj7k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc6Q9D0%2FdJMcaflQW14%2FimIYiEhovYRgYiYoc2vj7k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;754&quot; height=&quot;296&quot; data-origin-width=&quot;754&quot; data-origin-height=&quot;296&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Noise란, 신호에 방해가 되는 대부분의 요소를 말한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터통신에서는 이 3가지 Impairment 중 특히 Noise에 더 집중하여 본다. SNR이라는 Signal에 대하여 얼마만큼의 Noise가 존재하는 지를 나타내는 SNR이라는 용어도 존재한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;690&quot; data-origin-height=&quot;577&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nwMVT/dJMcaakxrD7/xN7TwdnPu5tVRGiyiQQph1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nwMVT/dJMcaakxrD7/xN7TwdnPu5tVRGiyiQQph1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nwMVT/dJMcaakxrD7/xN7TwdnPu5tVRGiyiQQph1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnwMVT%2FdJMcaakxrD7%2FxN7TwdnPu5tVRGiyiQQph1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;690&quot; height=&quot;577&quot; data-origin-width=&quot;690&quot; data-origin-height=&quot;577&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SNR이 크려면, Signal의 power가 강하고, Noise의 power가 약해야하므로, 기존의 signal이 어느정도 잘 유지되는 모습이다. 반면에, SNR이 작다면 원본 signal의 모양이 잘 유지가 되지 않는다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Data Rate Limites&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;통신에서 가장 중요한 것은 속도이다. Data rate을 계산하기 위한 2가지 방법을 소개하는데, 하나는 Noise가 존재하지 않는 channel을 가정한 Nyquist의 공식이고, 하나는 Noise를 가정한 Shannon의 공식이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 Nyquist 공식이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;494&quot; data-origin-height=&quot;52&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cPTtpx/dJMcacCFJKv/kR4u7YcSnaKRCHnd23kPT1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cPTtpx/dJMcacCFJKv/kR4u7YcSnaKRCHnd23kPT1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cPTtpx/dJMcacCFJKv/kR4u7YcSnaKRCHnd23kPT1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcPTtpx%2FdJMcacCFJKv%2FkR4u7YcSnaKRCHnd23kPT1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;494&quot; height=&quot;52&quot; data-origin-width=&quot;494&quot; data-origin-height=&quot;52&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;L은 digital signal의 level을 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 Shannon 공식이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;637&quot; data-origin-height=&quot;60&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nGqGh/dJMcagkJUol/MGWBOurp2h58nQ9lO5Suh0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nGqGh/dJMcagkJUol/MGWBOurp2h58nQ9lO5Suh0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nGqGh/dJMcagkJUol/MGWBOurp2h58nQ9lO5Suh0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnGqGh%2FdJMcagkJUol%2FMGWBOurp2h58nQ9lO5Suh0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;637&quot; height=&quot;60&quot; data-origin-width=&quot;637&quot; data-origin-height=&quot;60&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Noise가 있는 것과 없는 것의 차이를 보면, 2를 곱해주지 않게 되고, level 대신 SNR을 사용하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시를 하나 들어보자. 1 MHz 크기의 bandwidth를 지니고, SNR이 63인 channel이 있다고 가정하자. 그러면 Shannon formula를 통해 최대 전송 속도를 구할 수 있다. 식으로 보면 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;677&quot; data-origin-height=&quot;44&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZXDBY/dJMcacJrT9s/EsRcTO6t4yTk13lRHsxjw0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZXDBY/dJMcacJrT9s/EsRcTO6t4yTk13lRHsxjw0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZXDBY/dJMcacJrT9s/EsRcTO6t4yTk13lRHsxjw0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZXDBY%2FdJMcacJrT9s%2FEsRcTO6t4yTk13lRHsxjw0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;677&quot; height=&quot;44&quot; data-origin-width=&quot;677&quot; data-origin-height=&quot;44&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 값은 최대 속도이므로, 약간 값을 낮추어 4 Mbps로 하여 Nyquist formula를 사용하면 digital signal을 전송할 때 정해야하는 level을 구할 수 있다. 물론 noise를 가정하지 않았을 때이다. 이를 식으로 보면 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;553&quot; data-origin-height=&quot;47&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bguCPI/dJMcabRgTPw/Pjnz88Gq0qFRBOsxzrK5Qk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bguCPI/dJMcabRgTPw/Pjnz88Gq0qFRBOsxzrK5Qk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bguCPI/dJMcabRgTPw/Pjnz88Gq0qFRBOsxzrK5Qk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbguCPI%2FdJMcabRgTPw%2FPjnz88Gq0qFRBOsxzrK5Qk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;553&quot; height=&quot;47&quot; data-origin-width=&quot;553&quot; data-origin-height=&quot;47&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Perofrmance&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터 통신에서 통신의 성능을 측정하는 척도가 되는 것이 뭐가 있을까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저, Bandwidth이다. 우리가 기존에 배웠던 Bandwidth in hertz를 포함하여, bps를 Bandwidth로 표현하기도 한다. 보통은 Bandwidth in hertz의 크기가 커지면 보낼 수 있는 signal의 범위가 커지기 때문에 Bandwidth in bps도 함께 커진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 Throghput이다. Bandwidth in bps가 의미하는 것은 잠재적인 최대의 속도를 의미하는 것이며, 실제 전송 속도는 Bandwidth와는 다르다. Througput은 실제 전송 속도를 의미하는데, 이는 전송 알고리즘에 의해 달라질 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 Latency, 즉 delay이다. Delay란, source에서 첫 bit를 보내기 시작한 순간부터, 전체 메세지가 destination에 완전히 도착할 때까지 걸리는 시간을 의미한다. 그리고 delay는 다음 네 가지 요소의 합이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;610&quot; data-origin-height=&quot;330&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cCSZHl/dJMcahcTbZ3/A6H7MtSY4rBD5lpLv77Yuk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cCSZHl/dJMcahcTbZ3/A6H7MtSY4rBD5lpLv77Yuk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cCSZHl/dJMcahcTbZ3/A6H7MtSY4rBD5lpLv77Yuk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcCSZHl%2FdJMcahcTbZ3%2FA6H7MtSY4rBD5lpLv77Yuk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;610&quot; height=&quot;330&quot; data-origin-width=&quot;610&quot; data-origin-height=&quot;330&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Propagation time&lt;br /&gt;Signal이 transimission medium을 통해 이동하는데 걸리는 시간이다. 거리가 멀어지면 propagation time이 커진다&lt;br /&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;524&quot; data-origin-height=&quot;33&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xpkdi/dJMcagZliKz/vHd3gMvykfGwqsHVw6WM81/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xpkdi/dJMcagZliKz/vHd3gMvykfGwqsHVw6WM81/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xpkdi/dJMcagZliKz/vHd3gMvykfGwqsHVw6WM81/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fxpkdi%2FdJMcagZliKz%2FvHd3gMvykfGwqsHVw6WM81%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;524&quot; height=&quot;33&quot; data-origin-width=&quot;524&quot; data-origin-height=&quot;33&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/li&gt;
&lt;li&gt;Transmission time&lt;br /&gt;메세지의 비트들을 채널에 밀어넣는 데 걸리는 시간이다. 파일이 크면 transmission time이 커진다.&lt;br /&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;601&quot; data-origin-height=&quot;42&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cue4XN/dJMcaakxtzd/LRQKUUa9HD5WyNNSOGGw9K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cue4XN/dJMcaakxtzd/LRQKUUa9HD5WyNNSOGGw9K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cue4XN/dJMcaakxtzd/LRQKUUa9HD5WyNNSOGGw9K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcue4XN%2FdJMcaakxtzd%2FLRQKUUa9HD5WyNNSOGGw9K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;601&quot; height=&quot;42&quot; data-origin-width=&quot;601&quot; data-origin-height=&quot;42&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/li&gt;
&lt;li&gt;Device processing time&lt;br /&gt;Source에서 destination까지 여러개의 switch, router를 거칠 수도 있는데, 이때, 다음 경로를 구하는 데 걸리는 시간이다. 장비가 바쁘거나 복잡하면 processing delay가 커진다.&lt;/li&gt;
&lt;li&gt;Queuing delay&lt;br /&gt;Router에는 input과 output이 있는데, input이 꽉차게 되면 packet이 손실되고 하는데, 이 input의 대기 공간을 queue라고 한다. 이 queue에 대기하는 시간을 의미한다. 네트워크가 막히면 queuing time이 커진다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시를 하나 들어보자, 메세지를 보내는데, 다음과 같은 상황을 가정해보자.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메시지 크기 = 2.5 KB&lt;/li&gt;
&lt;li&gt;Bandwidth = 1 Gbps&lt;/li&gt;
&lt;li&gt;거리 = 12,000 km&lt;/li&gt;
&lt;li&gt;전파 속도 = 2.4 x 10^8 m/s&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;620&quot; data-origin-height=&quot;76&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/s4UaA/dJMcabwXP1O/kLwD0JAsd9d6tOCQIKKay0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/s4UaA/dJMcabwXP1O/kLwD0JAsd9d6tOCQIKKay0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/s4UaA/dJMcabwXP1O/kLwD0JAsd9d6tOCQIKKay0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fs4UaA%2FdJMcabwXP1O%2FkLwD0JAsd9d6tOCQIKKay0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;620&quot; height=&quot;76&quot; data-origin-width=&quot;620&quot; data-origin-height=&quot;76&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 상황에서 메시지는 짧고, Bandwidth가 매우 높기 때문에, transmission time보다는 propagation time이 더 지배적이다. 반대로, 메시지 크기가 크고 Bandwidth가 작은 경우를 가정해보자.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메시지 크기 = 5 MB&lt;/li&gt;
&lt;li&gt;Bandwidth = 1 Mbps&lt;/li&gt;
&lt;li&gt;거리 = 12,000 km&lt;/li&gt;
&lt;li&gt;전파 속도 = 2.4 x 10^8 m/s&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;625&quot; data-origin-height=&quot;78&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IpFWG/dJMcabcECBg/khzUC4YXvbQEkQmG3Kzjq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IpFWG/dJMcabcECBg/khzUC4YXvbQEkQmG3Kzjq1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IpFWG/dJMcabcECBg/khzUC4YXvbQEkQmG3Kzjq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIpFWG%2FdJMcabcECBg%2FkhzUC4YXvbQEkQmG3Kzjq1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;625&quot; height=&quot;78&quot; data-origin-width=&quot;625&quot; data-origin-height=&quot;78&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 상황에서는 propagation time보다 transmission time이 더 지배적인 것을 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>CS/데이터통신</category>
      <author>PiLove</author>
      <guid isPermaLink="true">https://pi-love0314.tistory.com/46</guid>
      <comments>https://pi-love0314.tistory.com/entry/%EB%8D%B0%EC%9D%B4%ED%84%B0%ED%86%B5%EC%8B%A0-Week5-6-%EC%9D%B4%EB%A1%A0-Physical-layer#entry46comment</comments>
      <pubDate>Mon, 30 Mar 2026 20:51:11 +0900</pubDate>
    </item>
    <item>
      <title>[운영체제및실습] Week4. Thread</title>
      <link>https://pi-love0314.tistory.com/entry/%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C%EB%B0%8F%EC%8B%A4%EC%8A%B5-Week4-%EC%9D%B4%EB%A1%A0-Thread</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;충남대학교 류재철 교수님, 운영체제 및 실습 과목 4주차 정리입니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Preview&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로그램을 실행하면 OS는 process를 생성한다. 이 과정에서 새로운 프로그램을 실행하려면 기존 process를 fork()를 하게된다. 일반적인 프로그램이라면 fork()를 하고 exec()을 하는 것만으로 충분하지만, 게임 같은 프로그램의 경우에는 동일한 데이터(맵 정보, 캐릭터 위치, 아이템 상태 등)를 서로 다른 process가 공유하며 실시간으로 처리해야 한다. 따라서 이러한 경우 process는 서로 독립된 메모리 공간을 가지므로 통신이 필요해진다. 이를 해결하기 위해 공유가 필요한 메모리 공간은 공유하고, 나누어야 할 부분은 나누어 작업하는 thread가 탄생하게 되었다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Thread&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Thread란 무엇일까? Thread란 일종의 실행흐름을 의미한다. 한 process 내에서 새로운 thread가 만들어지면, 새로운 작업이 시작되며 새로운 실행흐름이 만들어진다. 이게 어떤 도움이 될까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 1부터 1000조까지 더하는 작업을 수행한다고 가정하자. 연산량이 꽤 많이 들을 것이다. 이것을 single process에 single thread로 해결하려고 하면 이 모든 연산량을 하나의 실행흐름으로 감당해야 한다. 그러나, single process에 multi thread로 해결한다고 하면, 여러개의 실행흐름을 통해 연산량을 n개의 thread로 나누어 처리할 수 있게 된다. 이는 곧 실행 속도도 약 n배 빨라진다고 볼 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;355&quot; data-origin-height=&quot;356&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bh3xVM/dJMcagSqNcC/LZuN6S2Q4ky8ireYHnM5ck/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bh3xVM/dJMcagSqNcC/LZuN6S2Q4ky8ireYHnM5ck/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bh3xVM/dJMcagSqNcC/LZuN6S2Q4ky8ireYHnM5ck/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbh3xVM%2FdJMcagSqNcC%2FLZuN6S2Q4ky8ireYHnM5ck%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;355&quot; height=&quot;356&quot; data-origin-width=&quot;355&quot; data-origin-height=&quot;356&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Process가 생성되면 위와 같은 그림처럼 OS가 PCB, 그리고 메모리 맵을 할당해준다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Process와 Thread의 생성에서 큰 차이점은 바로 thread는 stack만 독립된 메모리 공간으로 할당하고, PCB, HEAP, DATA, CODE를 공유한다는 점이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;459&quot; data-origin-height=&quot;348&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cYeBXS/dJMcaiiojNo/jmNHvmxzYT0HsTxaC5JjLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cYeBXS/dJMcaiiojNo/jmNHvmxzYT0HsTxaC5JjLK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cYeBXS/dJMcaiiojNo/jmNHvmxzYT0HsTxaC5JjLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcYeBXS%2FdJMcaiiojNo%2FjmNHvmxzYT0HsTxaC5JjLK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;459&quot; height=&quot;348&quot; data-origin-width=&quot;459&quot; data-origin-height=&quot;348&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이로 인해 얻을 수 있는 효과는 무엇일까? Process의 종류에 따라 시간이 오래 걸리거나 여러 host가 필요한 작업의 경우, 공유가 필요한 작업은 공유하고 그 외에 작업은 병렬적으로 실행이 가능하다는 것이다. 위 사진에서 HEAP, DATA, CODE는 각 thread가 모두 공유하고 있다고 생각하면 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;668&quot; data-origin-height=&quot;522&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0IC0Y/dJMcagkzgaY/A0gTP1BRWUPhiX0XS0VZJ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0IC0Y/dJMcagkzgaY/A0gTP1BRWUPhiX0XS0VZJ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0IC0Y/dJMcagkzgaY/A0gTP1BRWUPhiX0XS0VZJ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0IC0Y%2FdJMcagkzgaY%2FA0gTP1BRWUPhiX0XS0VZJ0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;668&quot; height=&quot;522&quot; data-origin-width=&quot;668&quot; data-origin-height=&quot;522&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 그림은 RPC Request를 2번 수행하는 process를 2개의 thread로 병렬적으로 작업하였을 때 얻을 수 있는 효과를 나타낸 그림이다. Thread를 2개 실행하게 되면서 RPC Request를 병렬적으로 한번에 2개를 처리하게 되어, 약 2배 빠른 성능 향상을 체감할 수 있다. 다만 주의해야할 점은, processor가 코어가 하나뿐이 uniprocessor이므로, thread B가 RPC Request가 끝난 이후 종료를 위해 processor를 점유하게 되면 thread A는 잠시 wait해야 한다는 점이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 의문이 들 수 있는 점이.. thread의 장점이 병렬성인데 processor를 사용하는 작업은 병렬적으로 처리하는 것이 불가능하다는 것이다. 사실 이는 ULT와 KLT에 대해 알면 이해하기 쉬우니 우선은 넘어가고 뒤에서 정리하도록 하겠다. 아무튼 코어가 하나뿐인 uniprocessor라서, processor를 사용하는 작업이 병렬적으로 처리하기 어렵다는 것만 알아두자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;782&quot; data-origin-height=&quot;387&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uIF7N/dJMcaiCGiaf/kETC7gLpbUTkhuAPcMlub1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uIF7N/dJMcaiCGiaf/kETC7gLpbUTkhuAPcMlub1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uIF7N/dJMcaiCGiaf/kETC7gLpbUTkhuAPcMlub1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuIF7N%2FdJMcaiCGiaf%2FkETC7gLpbUTkhuAPcMlub1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;782&quot; height=&quot;387&quot; data-origin-width=&quot;782&quot; data-origin-height=&quot;387&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Uniprocessor를 기준으로 multi thread의 동작을 설명한 그림이다. 역시나 processor를 사용한 작업에 대해 병렬적으로 처리하는 모습은 보이지 않는다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Thread의 실행&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Process가 생성될 때를 기억하는가?&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;fork()&lt;/li&gt;
&lt;li&gt;PCB 생성, 메모리맵 생성&lt;/li&gt;
&lt;li&gt;exec()&lt;/li&gt;
&lt;li&gt;CPU 스케줄러가 인식=&lt;/li&gt;
&lt;li&gt;Dispatcher가 CPU를 할당하여 process 실행&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 과정처럼 thread 또한 생성되는 데에 꽤 복잡한 과정을 거친다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;clone()&lt;/li&gt;
&lt;li&gt;TCB 생성, 독립적인 Stack 할당&lt;/li&gt;
&lt;li&gt;CPU 스케줄러가 인식&lt;/li&gt;
&lt;li&gt;Dispatcher에 의해 CPU 할당&lt;/li&gt;
&lt;/ol&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Multi thread의 문제&amp;nbsp;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Multi thread의 장점은 지금까지 많이 알아보았다. 그러나 multi thread를 사용할 때 유의해야 하는 점이 있는데, 바로 race condition이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Race condition이란, 여러 thread가 같은 공유 데이터, 즉, PCB, CODE, HEAP, DATA 영역에 동시에 접근하게 되어, 실행 순서에 따라 결과가 달라지는 문제를 의미한다. 이름 그대로 thread끼리 race를 하게 되는 경우이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시로 은행을 생각해보자. 계좌 잔액이 10,000원이라고 하자. 두 thread가 완전 동시에 1,000원을 인출하게 되면 계좌 잔액이 8,000원이 되어야 하는데 9,000원이 되어버린다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 해결하기 위한 방법이 mutext이다. mutex는 mutual exclusion의 줄임말이다. 뜻은 그 이름 그대로 thread끼리 상호 간에 배제하는 것이다. 즉, 공유하는 데이터에 대하여 한 번에 하나의 thread만 들어오게 막는 장치이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시 은행을 예시로 들어보자. Thread A가 잔액을 수정하기 전까지는 lock을 획득하고 작업을 수행한다. 그리고 끝나면 unlock하는 것이다. 이러면 thread B는 lock이 풀릴 때까지 기다렸다가 작업을 수행해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 또 mutex를 무조건 많이 쓰는 게 좋지만도 않다. 왜냐하면 lock을 걸면 다른 thread가 기다려야 해서 병렬성이 줄어들 수 있기 때문이다. 즉, 안정성은 올라가는 대신 성능이 떨어질 수도 있다.&amp;nbsp;&lt;br /&gt;또한 deadlock 문제가 발생할 수 있다. 만약 공유 자원에 정말정말 동시에 들어가게 되면 두 thread가 한번에 lock을 잡게 되는 경우도 있다. 이러한 경우 두 thread가 상대 thread의 unlock을 기다리면서 영원히 멈출 수 있다. 이러한 경우를 deadlock이라고 한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>CS/운영체제및실습</category>
      <author>PiLove</author>
      <guid isPermaLink="true">https://pi-love0314.tistory.com/45</guid>
      <comments>https://pi-love0314.tistory.com/entry/%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C%EB%B0%8F%EC%8B%A4%EC%8A%B5-Week4-%EC%9D%B4%EB%A1%A0-Thread#entry45comment</comments>
      <pubDate>Tue, 24 Mar 2026 19:37:44 +0900</pubDate>
    </item>
    <item>
      <title>[데이터통신] Week4-5. Networks Model</title>
      <link>https://pi-love0314.tistory.com/entry/OC-%EC%9D%B4%EB%A1%A0-Week4-5-Networks-Model</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;충남대학교 김기일 교수님, 데이터통신 4~5주차 정리입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터통신에서 layer(계층)란 무엇일까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;통신은 그 과정이 매우 복잡하다. 여러 과정을 거쳐서 수신자와 송신자가 데이터를 교환하게 된다. 만약, 이 과정들을 한번에 처리하려고 하면 어떨까? 과정이 복잡하다보니 특정 기능을 개발하거나 수정하려다가 다른 기능에까지 영향을 줄 수 있다. 따라서 복잡한 과정을 여러 개의 작은 단계로 나누어 모듈화하여 관리하는 방식으로 통신을 진행하게 되었다. 이를 layer(계층)라고 한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Protocol Layering&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Protocol이란, 송신자와 수신자 그리고 router, switch 등의 장치들이 따라야 하는 일종의 규칙을 의미한다. 통신이 단순하다면 하나의 protocol을 정의하는 것으로 충분하겠지만, 복잡한 통신은 각 layer마다 protocol이 필요하다. 이를 Protocol layering이라고 한다. 통신을 위한 네트워크에서는 &quot;누가 먼저 말할지&quot;, &quot;주소를 어떻게 적을지&quot;, &quot;오류가 나면 어떻게 처리할지&quot; 등과 같은 규칙이 필요하다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단한 예시를 들어, 마리아와 앤이 통신을 한다고 가정하자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;749&quot; data-origin-height=&quot;176&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vP8Ky/dJMcabDzrlQ/Uvit4oI1ckLfVR70DmydpK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vP8Ky/dJMcabDzrlQ/Uvit4oI1ckLfVR70DmydpK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vP8Ky/dJMcabDzrlQ/Uvit4oI1ckLfVR70DmydpK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvP8Ky%2FdJMcabDzrlQ%2FUvit4oI1ckLfVR70DmydpK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;749&quot; height=&quot;176&quot; data-origin-width=&quot;749&quot; data-origin-height=&quot;176&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 둘은 거리가 가까워서 공기를 매개로 말이 곧잘 전달된다. 즉, 이러한 단순한 통신에서는 추가적인 layer없이도 single layer로 충분하다는 의미이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Single layer에서도 protocol은 존재한다. 예를 들어, &quot;만나면 인사를 한다&quot;, &quot;관계 수준에 맞는 어휘를 사용한다&quot;, &quot;말을 자르지 않는다&quot; 등 마리아와 앤이 암묵적으로 스스로 생각하고 있는 일종의 마지노선, 즉 protocol이 존재한다. 통신에는 layer의 깊이에 상관없이 항상 protocol이 존재하는 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;795&quot; data-origin-height=&quot;441&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nEtK6/dJMcaaq7YDr/CU7EgqnUJgkwIVDDkFDzsK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nEtK6/dJMcaaq7YDr/CU7EgqnUJgkwIVDDkFDzsK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nEtK6/dJMcaaq7YDr/CU7EgqnUJgkwIVDDkFDzsK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnEtK6%2FdJMcaaq7YDr%2FCU7EgqnUJgkwIVDDkFDzsK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;795&quot; height=&quot;441&quot; data-origin-width=&quot;795&quot; data-origin-height=&quot;441&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번엔 &quot;우편&quot;을 이용한 통신을 예로 들어보자. 대면으로 통신을 하는 경우와 비교하여 통신이 복잡해졌다. 일종의 시나리오를 생각해보자. 마리아와 앤은 우편을 통한 통신을 하기 때문에, 첫번째로 우편을 작성하는 기능이 필요하다. 이를 가장 상위 layer가 될 것이다. 두번째로 마리아와 앤을 제외한 다른 사람이 이 우편을 읽지 못하게 하기 위한 Encrypt/Decrypt(암호화/복호화) 기능이 필요하다. 이는 그 다음 layer가 될 것이다. 마지막으로는 암호화를 완료한 우편을 상대방에게 전달하기 위한 전달 기능이 필요하다. 이게 마지막 layer가 될 것이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 단계별로 정리하면 다음과 같다. 마리아가 송신을 하고 앤이 수신을 한다고 가정하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 마리아의 경우이다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;마리아가 layer 3에서 plain text(우편)을 작성한다.&lt;/li&gt;
&lt;li&gt;layer 2에서 plain text를 Encrypt하여 ciphertext(암호문)을 생성한다.&lt;/li&gt;
&lt;li&gt;layer 1에서 이 ciphertext를 봉투에 넣고 주소를 써서 앤측으로 발송한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 앤의 경우이다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;layer 1에서 수신받은 봉투에서 ciphertext를 꺼낸다.&lt;/li&gt;
&lt;li&gt;layer 2에서 이 ciphertext를 Decrypt하여 plaintext를 생성한다.&lt;/li&gt;
&lt;li&gt;layer 3에서 앤이 이 내용을 읽고 통신을 완료한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 알 수 있듯이, 각각의 layer는 서로다른 작업을 수행한다. 따라서 각 작업별로 유지보수 및 수정이 용이하다. 예를들어, 마리아와 앤이 Encrypt/Decrypt 하는 과정이 다른 사람에 공유되어서 다른 사람이 마리아의 우편을 볼 수 있게되었다고 가정하자. 이러한 경우에, 통신 전체를 손볼 것이 아니라 Encrypt/Decrypt 즉, layer 2만 변경해도 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 그림에서 아직 설명 안한 부분이 마리아와 앤이 가지는 각각의 layer는 서로 logical connection을 가진다. 실제 데이터(우편)는 가장 낮은 계층을 통해 이동하지만, 논리적, 개념적으로는 같은 layer끼리 통신하는 것처럼 본다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;770&quot; data-origin-height=&quot;391&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4pHtO/dJMcagrkmbU/MkOhH7LqCa6MG2mg9vbwS1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4pHtO/dJMcagrkmbU/MkOhH7LqCa6MG2mg9vbwS1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4pHtO/dJMcagrkmbU/MkOhH7LqCa6MG2mg9vbwS1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4pHtO%2FdJMcagrkmbU%2FMkOhH7LqCa6MG2mg9vbwS1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;770&quot; height=&quot;391&quot; data-origin-width=&quot;770&quot; data-origin-height=&quot;391&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Layer 3에서는 plaintext를 기준으로 logical connection, layer 2에서는 ciphertext를 기준으로, layer 1에서는 mail을 기준으로 connection이 있다고 보는 것이다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;659&quot; data-origin-height=&quot;308&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UxpHH/dJMcadVDsKd/9pyzdqVg543eF83wYLdZD0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UxpHH/dJMcadVDsKd/9pyzdqVg543eF83wYLdZD0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UxpHH/dJMcadVDsKd/9pyzdqVg543eF83wYLdZD0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUxpHH%2FdJMcadVDsKd%2F9pyzdqVg543eF83wYLdZD0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;659&quot; height=&quot;308&quot; data-origin-width=&quot;659&quot; data-origin-height=&quot;308&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 그림은 인접한 layer 사이의 관계를 나타낸 그림이다. 송신을 기준으로 설명하면, N+1 layer에서는 데이터를 provide하고, N layer에서는 그 데이터를 use한다. 반대로 수신을 기준으로 설명하면, N layer에서 데이터를 provide하고, N+1 layer에서 그 데이터를 use한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;TCP/IP Protocol Suite&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;흔히 잘 알고있는 Internet에서 사용하는 protocol이 바로 TCP/IP Protocol이다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;749&quot; data-origin-height=&quot;480&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cuAHre/dJMcahcHwnE/kAl6HyyouB6bQtQ3SpKVOK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cuAHre/dJMcahcHwnE/kAl6HyyouB6bQtQ3SpKVOK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cuAHre/dJMcahcHwnE/kAl6HyyouB6bQtQ3SpKVOK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcuAHre%2FdJMcahcHwnE%2FkAl6HyyouB6bQtQ3SpKVOK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;749&quot; height=&quot;480&quot; data-origin-width=&quot;749&quot; data-origin-height=&quot;480&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 protocol은 자료에 따라서 4개의 layer로 보기도 하고, 5개의 layer로 보기도 한다. 수업에서는 오른쪽 그림으로 설명해주셨다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같은 구조를 가지는데... 실제로 TCP/IP는 두 host 사이의 통신을 어떻게 제어하는지 확인해보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;787&quot; data-origin-height=&quot;492&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/H0drS/dJMcacP0tSb/ISZieuYyLfleyzbS78mQzk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/H0drS/dJMcacP0tSb/ISZieuYyLfleyzbS78mQzk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/H0drS/dJMcacP0tSb/ISZieuYyLfleyzbS78mQzk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FH0drS%2FdJMcacP0tSb%2FISZieuYyLfleyzbS78mQzk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;787&quot; height=&quot;492&quot; data-origin-width=&quot;787&quot; data-origin-height=&quot;492&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 그림은 A와 B라는 host가 TCP/IP를 이용하여 통신하는 과정을 나타낸 그림이다. A와 B는 서로 다른 네트워크에 존재한다. 그렇다면 어떻게 통신이 가능할까? Switch와 router 덕분이다. Switch는 같은 네트워크 내의 서로 다른 LAN을 연결하는 역할을 한다. 그리고 router는 이러한 switch들은 연결하여 서로 다른 네트워크를 연결하는 역할을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 TCP/IP의 각 layer에서 정확히 어떤 일을 하는 지 알아보자. 이 과정에서 switch와 router의 layer가 A와 B의 layer 보다 적은 이유도 알아볼 것이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Physical layer :&lt;br /&gt;말 그대로 물리적인 매체를 통한 송수신 기능을 수행한다. 케이블, 전압, 주파수, 광신호 같은 진짜 물리 매체를 통해 0과 1을 실제 신호로 바꿔 보내게 된다.&lt;/li&gt;
&lt;li&gt;Data link layer :&lt;br /&gt;Physical layer에서 송수신한 데이터에 오류는 없는지 검출 및 처리하는 기능을 수행한다.&lt;/li&gt;
&lt;li&gt;Network layer :&lt;br /&gt;Host와 host 사이를 연결하는 layer로 중간에 router가 있을 경우, router의 Network layer에서 최적의 루트를 찾아주는 기능을 수행한다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Transport layer :&lt;br /&gt;Network layer에서의 error를 control하는 역할을 수행한다.&lt;/li&gt;
&lt;li&gt;Application layer :&lt;br /&gt;Host가 실제로 사용하는 웹 브라우저, 이메일 등의 프로그램을 의미한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 각각의 layer는 서로 다른 기능을 수행하며, 다루는 데이터의 단위도 달라진다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;759&quot; data-origin-height=&quot;375&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pr72V/dJMcahqfMD3/tnzyXBy3HoUcnF9dHBRWtk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pr72V/dJMcahqfMD3/tnzyXBy3HoUcnF9dHBRWtk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pr72V/dJMcahqfMD3/tnzyXBy3HoUcnF9dHBRWtk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fpr72V%2FdJMcahqfMD3%2FtnzyXBy3HoUcnF9dHBRWtk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;759&quot; height=&quot;375&quot; data-origin-width=&quot;759&quot; data-origin-height=&quot;375&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 layer에서 데이터를 provide, use하는 과정을 이해하기 위해선 packet에 대해서도 알아야 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;359&quot; data-origin-height=&quot;134&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1YFb2/dJMcajnZacD/J3Z0LKQ3rC7M5jzhoijHrK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1YFb2/dJMcajnZacD/J3Z0LKQ3rC7M5jzhoijHrK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1YFb2/dJMcajnZacD/J3Z0LKQ3rC7M5jzhoijHrK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1YFb2%2FdJMcajnZacD%2FJ3Z0LKQ3rC7M5jzhoijHrK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;359&quot; height=&quot;134&quot; data-origin-width=&quot;359&quot; data-origin-height=&quot;134&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Packet은 상위 layer(N+1)에서 하위 layer(N)에 보낸 data와 layer(N)에서 다음 layer (N-1)에 필요한 추가적인 정보인 header를 더하여 만들어진다. 이러한 과정은 physical layer에 도달하기 전까지 모든 인접한 layer에서 이루어진다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;792&quot; data-origin-height=&quot;364&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bqxpCn/dJMcadBiIzE/gR5B6wLKMvyFQV3Pk8HZi1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bqxpCn/dJMcadBiIzE/gR5B6wLKMvyFQV3Pk8HZi1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bqxpCn/dJMcadBiIzE/gR5B6wLKMvyFQV3Pk8HZi1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbqxpCn%2FdJMcadBiIzE%2FgR5B6wLKMvyFQV3Pk8HZi1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;792&quot; height=&quot;364&quot; data-origin-width=&quot;792&quot; data-origin-height=&quot;364&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그림은 data에 header가 계속해서 붙고, 제거되는 과정을 나타낸 그림이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;송신자 측에서는 상위 계층에서 하위 계층으로 데이터를 전달하기 위해 필요한 정보를 header에 계속해서 추가하고 전달하게 되고, physical layer에서는 이러한 packet을 router에 전달하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;Router에서는 입력받은 packet에 대하여 각각의 layer에 해당하는 header를 읽고 제거한다. Data link lyaer에서는 2번 header를 읽고 data link layer 사이의 protocol에 맞게 header에서 읽은 정보를 토대로 특정 action을 수행한다. 이후 header를 벗겨서 상위 layer로 packet을 전달한다. Router의 network layer에서는 network header를 확인하여 다음 경로를 결정한다. 이후 packet은 하위의 data link layer로 전달되고, data link layer에서는 다음 link에 맞는 새로운 data link header를 추가한다. &lt;/span&gt;&amp;nbsp;그리고 이 packet은 physical layer로 전달되어 비트를 전송하게 되고 수신자 측으로 전달된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수신자측에서는 physcial layer를 통해 들어온 packet을 상위 layer로 전달하고 각 layer에 맞는 header를 읽고 해당 layer에 정해진 protocol에 맞게 header에서의 정보를 토대로 특정 action을 수행한다. 그리고 읽은 header는 제거하여 상위 layer로 전달한다. 가장 마지막 상위 layer에서는 전체 header가 제거된 message를 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상위 layer에서 하위 layer로 데이터를 보낼 때 header로 감싸는 과정을 Encapsulation, 하위 layer에서 상위 layer로 데이터를 보낼 때 header를 제거하는 과정을 Decapsulation이라고 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1325&quot; data-origin-height=&quot;811&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b48Myj/dJMcaa5O597/wTkqOko5B9ZhlOl4Wpuf4K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b48Myj/dJMcaa5O597/wTkqOko5B9ZhlOl4Wpuf4K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b48Myj/dJMcaa5O597/wTkqOko5B9ZhlOl4Wpuf4K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb48Myj%2FdJMcaa5O597%2FwTkqOko5B9ZhlOl4Wpuf4K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1325&quot; height=&quot;811&quot; data-origin-width=&quot;1325&quot; data-origin-height=&quot;811&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 각 layer에서 다음 layer로 packet을 전달하기 위해 사용하는 address가 존재한다. Physcial layer의 bit 자체는 주소를 가질 수 없기 때문에 보통 4종류의 address를 가정한다. 각각의 layer마다 address가 존재하는 이유는, layer마다 수행하는 작업이 다르기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, Application layer에서는 &quot;어떤 서비스/이름을 찾는가&quot;가 중요해서 Names라는 address를 사용하고, Transport layer에서는 &quot;그 컴퓨터 안의 어떤 process인가&quot;가 중요해서 port number를 사용한다. Network layer에서는 &quot;어느 호스트까지 갈 것인가&quot;가 중요해서 logical address(IP 주소)를 사용하고, Data link layer에서는 &quot;지금 이 링크에서 바로 누구에게 넘길 것인가&quot;가 중요해서 link layer address(MAC 주소)를 사용한다. Physical layer에서는 변환한 bit 신호 자체를 보내는 layer이기 때문에 주소를 따로 두지 않는다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1228&quot; data-origin-height=&quot;417&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b80WgS/dJMcadBowdM/qCTPYGCnWN2gMDLI6knJck/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b80WgS/dJMcadBowdM/qCTPYGCnWN2gMDLI6knJck/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b80WgS/dJMcadBowdM/qCTPYGCnWN2gMDLI6knJck/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb80WgS%2FdJMcadBowdM%2FqCTPYGCnWN2gMDLI6knJck%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1228&quot; height=&quot;417&quot; data-origin-width=&quot;1228&quot; data-origin-height=&quot;417&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TCP/IP protocol의 또 하나의 장점 중 하나가 바로 Multiplexing/Demultiplexing 기능이다. Application layer에는 다양한 protocol이 존재한다. FTP, HTTP, ... 또는 DNS, SNMP, ... 등, 이러한 다양한 protocol이 공통으로 사용가능한 protocol이 존재한다. 그게 바로 Transport layer의 protocol인 TCP/UDP이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Application layer의 다양한 protocol을 Transport layer의 TCP/UDP로 모으고, TCP/UDP는 IP라는 Network layer의 protocol로 모이게 되어 하위 layer로 전달된다. 이 과정을 Multiplexing이라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Demultiplexing은 수신 측에서 하위 layer의 하나의 protocol이 받은 데이터를 해석하여, 그것을 알맞은 여러 상위 layer의 protocol 중 하나로 올려 보내는 과정이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 컴퓨터는 동시에 여러 프로그램이 네트워크를 사용할 수 있으므로, Applcation layer에서 서로 다른 protocol을 사용할 수도 있다. 따라서 Multiplexing/Demultiplexing을 통해 충돌없이 통신할 수 있게 하는 것이 중요하다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;OSI Model&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1249&quot; data-origin-height=&quot;773&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ckPWI4/dJMcadIcbn9/PTgtcoDkylPUs0wFv1r7q0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ckPWI4/dJMcadIcbn9/PTgtcoDkylPUs0wFv1r7q0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ckPWI4/dJMcadIcbn9/PTgtcoDkylPUs0wFv1r7q0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FckPWI4%2FdJMcadIcbn9%2FPTgtcoDkylPUs0wFv1r7q0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1249&quot; height=&quot;773&quot; data-origin-width=&quot;1249&quot; data-origin-height=&quot;773&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OSI 모델은 위와 같은 구조로 7개의 layer로 이루어져 있다. TCP/IP와의 차이점으로는 TCP/IP의 Application layer를 3개의 layer로 나누었다는 점이다. OSI의 Presentatino layer에서는 Encryption(암호화)/Decryption(복호화) 작업을 수행하게 되고, Session layer에서는 통신 대상과의 session(대화 흐름)을 관리한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 모델이 등장한 순서를 생각해보면, OSI 모델이 나중에 나왔기 때문에 보통은 단점을 보완한 OSI 모델을 사용하지만, 다음과 같은 이유때문에 현재에도 TCP/IP 모델을 사용한다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;OSI가 나왔을 때 TCP/IP가 이미 자리 잡았고, 매몰된 시간과 비용이 많아서 바꾸기에는 큰 부담이 들었다.&lt;/li&gt;
&lt;li&gt;OSI의 일부 계층, 특히 presentation과 session 계층의 서비스에 대해 그 정의가 충분히 구체적이지 못했다.&lt;/li&gt;
&lt;li&gt;성능 상 큰 차이가 없었다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 이론적으로는 깔끔했지만, 실용성이 부족했다는 점이다. 따라서 OSI는 이론적으로 계층 구조를 더 세밀하게 바라보게 해주는 참조 모델 정도로 이해하고 넘어가면 된다.&amp;nbsp;&lt;/p&gt;</description>
      <category>CS/데이터통신</category>
      <author>PiLove</author>
      <guid isPermaLink="true">https://pi-love0314.tistory.com/44</guid>
      <comments>https://pi-love0314.tistory.com/entry/OC-%EC%9D%B4%EB%A1%A0-Week4-5-Networks-Model#entry44comment</comments>
      <pubDate>Mon, 23 Mar 2026 22:16:25 +0900</pubDate>
    </item>
    <item>
      <title>[C언어] 포인터 (매우) 간단하게 정리, Makefile 기본</title>
      <link>https://pi-love0314.tistory.com/entry/C%EC%96%B8%EC%96%B4-%ED%8F%AC%EC%9D%B8%ED%84%B0-%EB%A7%A4%EC%9A%B0-%EA%B0%84%EB%8B%A8%ED%95%98%EA%B2%8C-%EC%A0%95%EB%A6%AC-Makefile-%EA%B8%B0%EB%B3%B8</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;휴학하고 파이썬만 다루었더니 C는 다 까먹었다. 간단하게만 정리해두고 간간히 보자.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;포인터&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;선언에서 * : 주소를 저장하는 포인터 변수 (int *p = )&lt;/li&gt;
&lt;li&gt;사용(우변)에서 * : 해당 변수의 주소에 존재하는 값 반환 (a = *p)&lt;/li&gt;
&lt;li&gt;사용(우변)에서 &amp;amp; : 해당 변수의 주소 반환 (int *p = &amp;amp;b)&lt;/li&gt;
&lt;li&gt;배열 : 배열의 이름 자체가 주소처럼 동작(첫 번째 인덱스 주소)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Makefile&lt;/h2&gt;
&lt;pre id=&quot;code_1773830351121&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;CC = gcc
CFLAGS = -pthread
TARGET = DC_03_hw
SRC = DC_03_hw.c

all:
	$(CC) $(SRC) -o $(TARGET) $(CFLAGS)

clean:
	rm -f $(TARGET)&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CC : 사용할 컴파일러&lt;/li&gt;
&lt;li&gt;SRC : 컴파일할 소스코드 파일&lt;/li&gt;
&lt;li&gt;TARGET : 컴파일 후 파일 이름&lt;/li&gt;
&lt;li&gt;CFLAGS : 컴파일 할 때 추가할 옵션&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;make&quot; 로 바이너리 코드 파일(실행 파일) 생성, clean으로 삭제&lt;/p&gt;</description>
      <category>C, Python, ...</category>
      <author>PiLove</author>
      <guid isPermaLink="true">https://pi-love0314.tistory.com/41</guid>
      <comments>https://pi-love0314.tistory.com/entry/C%EC%96%B8%EC%96%B4-%ED%8F%AC%EC%9D%B8%ED%84%B0-%EB%A7%A4%EC%9A%B0-%EA%B0%84%EB%8B%A8%ED%95%98%EA%B2%8C-%EC%A0%95%EB%A6%AC-Makefile-%EA%B8%B0%EB%B3%B8#entry41comment</comments>
      <pubDate>Wed, 18 Mar 2026 19:42:11 +0900</pubDate>
    </item>
    <item>
      <title>[데이터통신] Week3. Introduction(2) &amp;amp; Networks Model overview</title>
      <link>https://pi-love0314.tistory.com/entry/DC-%EC%9D%B4%EB%A1%A0-Week3-Introduction2-Networks-Model-overview</link>
      <description>&lt;p style=&quot;background-color: #ffffff; color: #252525; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;충남대학교 김기일 교수님, 데이터통신 3주차 정리입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1309&quot; data-origin-height=&quot;676&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/drvj3S/dJMcagSjQMe/GNKztbejQFEKGDjpESHvb0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/drvj3S/dJMcagSjQMe/GNKztbejQFEKGDjpESHvb0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/drvj3S/dJMcagSjQMe/GNKztbejQFEKGDjpESHvb0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdrvj3S%2FdJMcagSjQMe%2FGNKztbejQFEKGDjpESHvb0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1309&quot; height=&quot;676&quot; data-origin-width=&quot;1309&quot; data-origin-height=&quot;676&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지난 시간에 LAN은 각각의 호스트들이 모여 만들어지고, WAN은 switch, router 같은 connection device가 모여 만들어진다고 배웠다. 이번 시간에는 이러한 switch, router가 어떤 기능을 수행하는 지와 Internet에 대해 간단하게 알아보려고 한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Switching&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;internet이란 여러 네트워크가 연결된 switched network이다. Switch는 적어도 두 개 이상의 네트워크를 연결한다. 이렇게 한 네트워크에서 다른 네트워크로 데이터를 전달하는 기술이 switching이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Switching에는 Circuit Switching과 Packet Switching 2개 종류가 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;625&quot; data-origin-height=&quot;398&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b23ckS/dJMcacPUK3E/wRMviV3J7CQZgWZqZPLjmK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b23ckS/dJMcacPUK3E/wRMviV3J7CQZgWZqZPLjmK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b23ckS/dJMcacPUK3E/wRMviV3J7CQZgWZqZPLjmK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb23ckS%2FdJMcacPUK3E%2FwRMviV3J7CQZgWZqZPLjmK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;625&quot; height=&quot;398&quot; data-origin-width=&quot;625&quot; data-origin-height=&quot;398&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Circuit Switching의 구조는 host와 host 사이에 switch를 통해 하나의 고정된 회선으로 전용 경로를 설정하여 통신을 한다. 통신 전에 두 단말 사이에 전용 경로를 먼저 설정하고, 통신 중에는 해당 경로를 계~속 사용한다. 이 과정에서 해당 경로의 대역폭이 예약되기 때문에 다른 통신이 그 자원을 사용하지 못한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Packet Switching는 host와 host 사이에 router를 통한 링크를 통해 동적인 경로로 통신을 한다. 라우터를 사용하여 데이터를 packet 단위로 나누어 queue에 저장 후 전송한다. 동적으로 경로를 찾기 때문에, 전송 과정에서 데이터를 어떤 경로로 전송하는 게 빠른지 계산하는 알고리즘이 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지난 시간에 배웠던 Jitter를 생각해보자... Circuit Switching 같은 경우는 Jitter가 even하게 들어올 것이다. 반면 Packet Switching은 데이터 전송 과정에서 router의 queue에서 packet이 대기하면서 delay가 달라지기 때문에 Jitter가 uneven하게 들어올 것이다. 그렇다면 Packet Switching은 왜 굳이 사용하는 걸까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바로 자원의 효율성 때문이다. Circuit Switching은 회선을 독점 사용하는 반면, Packet Switching은 네트워크를 여러 사용자가 공유한다. 예를 들어, A, B, C, D가 있다고 하자. A와 B 사이에 Circuit Switching 방식을 통해 회선을 점유하고 있으면, C, D는 해당 회선을 사용할 수 없다. 반면에 Packet Switching을 사용하게 되면, A -&amp;gt; packet, B -&amp;gt; packet, C -&amp;gt; packet, D -&amp;gt; packet 이런 식으로 같은 링크를 여러 사람이 사용하여 데이터를 전송할 수 있다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Internet&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;internet이란, 두 개 이상의 네트워크가 연결된 구조를 말한다. 이러한 internet 중 가장 주목할만한 internet이 바로 Internet이다. Internet은 수천개 이상의 네트워크로 구성된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;695&quot; data-origin-height=&quot;414&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oGnct/dJMcac99KJ1/4QLTeoSA7YmvLUsXRy4NMk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oGnct/dJMcac99KJ1/4QLTeoSA7YmvLUsXRy4NMk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oGnct/dJMcac99KJ1/4QLTeoSA7YmvLUsXRy4NMk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoGnct%2FdJMcac99KJ1%2F4QLTeoSA7YmvLUsXRy4NMk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;695&quot; height=&quot;414&quot; data-origin-width=&quot;695&quot; data-origin-height=&quot;414&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘 날 Internet의 구조는 다음과 같다. 우리가 흔히 사용하는 wifi는 Customer network에 해당한다. 이러한 Customer network가 여러 개 묶여 Provider network라고 부르고, 이러한 Provider network가 모여 Backbone을 구성한다. Backbone은 모든 network의 상위 계층으로, 이러한 계층 구조에서 상위 계층에 있는 네트워크일수록 신뢰성과 속도가 중요하기 때문에 Mesh topology를 사용하는 것이 좋다고 한당.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>CS/데이터통신</category>
      <author>PiLove</author>
      <guid isPermaLink="true">https://pi-love0314.tistory.com/40</guid>
      <comments>https://pi-love0314.tistory.com/entry/DC-%EC%9D%B4%EB%A1%A0-Week3-Introduction2-Networks-Model-overview#entry40comment</comments>
      <pubDate>Mon, 16 Mar 2026 23:13:01 +0900</pubDate>
    </item>
    <item>
      <title>[운영체제및실습] Week2. Operating System Overview</title>
      <link>https://pi-love0314.tistory.com/entry/OS-Week2Operating-System-Overview</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;충남대학교 류재철 교수님, 운영체제 및 실습 과목 2주차 정리입니다.&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;OS, Computer System의 발전과정&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Serial Processing&lt;br /&gt;과거엔 컴퓨터가 귀해서 10~11, 11~12, 12~13... 이런 식으로 여러 사용자가 시간을 나누어 컴퓨터를 사용했다. 이렇게 컴퓨터를 사용하다보니, 작업이 일찍 끝나거나 초과하게 되면 CPU가 놀게되고 다음 사용자가 대기해야하는 일이 빈번했다.&lt;/li&gt;
&lt;li&gt;Batch Processing&lt;br /&gt;따라서 여러 사용자들의 작업을 한번에 수행하기 위해 Batch Processing이 생겼다. 이제 개발자들은 컴퓨터에 작업을 모두 모아 순차적으로 실행함으로써 CPU가 노는 시간을 절약할 수 있게 되었다. 참고로 Main Memory 내에 Monitor 라는 OS의 시초격인 프로그램을 저장하여 하나의 프로그램의 시작과 끝을 확인하고 각각의 프로그램을 구분하여 실행할 수 있었다.&lt;br /&gt;이후, Punch 카드 형태의 입력기에서 키보드와 하드디스크가 개발되며 프로그램을 실행하기 위한 여러 준비과정이 생략되었다.&lt;/li&gt;
&lt;li&gt;Multi Programming&lt;br /&gt;Main Memory에 2개 이상의 프로그램을 올리는 것을 말한다. 2개 이상의 프로그램을 Main Memory에 올렸을 뿐이지, 두 프로그램이 동시에 실행되지는 않는다.&lt;/li&gt;
&lt;li&gt;Time Sharing&lt;br /&gt;Main memory에 2개 이상의 프로그램이 올라갔는데, 만약 프로그램1이 계속 실행되고 있다면 프로그램2는 실행되지 않을 것이다. 이러한 문제를 방지하고자 일정 제한 시간을 둠으로써, OS가 일정 시간이 지나면 프로그램1의 실행을 멈추고 프로그램2를 실행한다. 이를 Context Switching이라고 한다.&lt;/li&gt;
&lt;li&gt;Multi Processing&lt;br /&gt;이제는 2개 이상의 Processor를 가지고 병렬적으로 프로그램을 실행할 수 있게 되었다.&lt;/li&gt;
&lt;li&gt;Parallel Processing&lt;br /&gt;프로그램 하나를 2개 이상의 Processor로 돌리는 것을 말한다. 그러나, 프로그램을 2개의 Processor로 돌리기 위해선 프로그램 코드를 작성하는 데에 있어서 어려움이 있다.&lt;/li&gt;
&lt;li&gt;Distributed Computing&lt;br /&gt;컴퓨터는 지금까지 빠른 속도를 추구하며 발전해왔다. 이 당시 네트워크가 보급되며, 한 컴퓨터의 자원을 다른 컴퓨터가 사용할 수 있도록하면 더 빠른 속도로 작업을 수행할 수 있지 않을까? 하는 아이디어로 나타났다. 그러나 서로 다른 H/W 환경으로 인해 큰 효과를 얻지는 못했다. 지금은 다른 방향으로 활용하고 있다고 한다.&lt;/li&gt;
&lt;li&gt;Cloud Computing&lt;br /&gt;오늘 날 사용하는 중앙 집중화된 컴퓨팅 작업 환경이다. 클라우드 서비스를 통해 큰 서버를 대여하여 활용할 수 있다.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;OS Overview&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;137&quot; data-origin-height=&quot;197&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cw9kuo/dJMcaioZUV0/iK6NKAkY8PgAExhnk04LkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cw9kuo/dJMcaioZUV0/iK6NKAkY8PgAExhnk04LkK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cw9kuo/dJMcaioZUV0/iK6NKAkY8PgAExhnk04LkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcw9kuo%2FdJMcaioZUV0%2FiK6NKAkY8PgAExhnk04LkK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;166&quot; height=&quot;239&quot; data-origin-width=&quot;137&quot; data-origin-height=&quot;197&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;br /&gt;사용자가 command를 입력하면, command interpreter가 명령어를 해석하고, 이에 해당하는 system call을 가져다가 instruction으로 H/W에 전달한다.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;이를 자세히 정리하면 아래 사진과 같다. Application programs를 통해 명령어가 들어오고, Command Interpreter를 통해 OS가 System call을 불러서 Instruction으로 H/W에 전달한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;591&quot; data-origin-height=&quot;328&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blOUbH/dJMcaibtida/ymOpXNqdPWDojqH3L18rCK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blOUbH/dJMcaibtida/ymOpXNqdPWDojqH3L18rCK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blOUbH/dJMcaibtida/ymOpXNqdPWDojqH3L18rCK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblOUbH%2FdJMcaibtida%2FymOpXNqdPWDojqH3L18rCK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;591&quot; height=&quot;328&quot; data-origin-width=&quot;591&quot; data-origin-height=&quot;328&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;%edit myfile.txt 라는 명령어에 대해 어떤 과정을 거치는지 알아보자.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;keyboard device driver&lt;/li&gt;
&lt;li&gt;command interpreter&lt;br /&gt;명령어를 해석&lt;/li&gt;
&lt;li&gt;loader editor&lt;br /&gt;editor라는 프로그램을 하드디스크에서 찾아서 메인메모리로 로드&lt;/li&gt;
&lt;li&gt;editor process creation&lt;br /&gt;- fork() system call&lt;/li&gt;
&lt;li&gt;CPU scheduling&lt;/li&gt;
&lt;li&gt;file open() system call&lt;/li&gt;
&lt;li&gt;editing&lt;/li&gt;
&lt;li&gt;file close() system call&lt;/li&gt;
&lt;li&gt;exit() system call&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;291&quot; data-origin-height=&quot;202&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/clh6HP/dJMcac3lsBK/HzOHqmsCsOkKg7E6ExACY0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/clh6HP/dJMcac3lsBK/HzOHqmsCsOkKg7E6ExACY0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/clh6HP/dJMcac3lsBK/HzOHqmsCsOkKg7E6ExACY0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fclh6HP%2FdJMcac3lsBK%2FHzOHqmsCsOkKg7E6ExACY0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;291&quot; height=&quot;202&quot; data-origin-width=&quot;291&quot; data-origin-height=&quot;202&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;System call이 발생하면 CPU는 메인 메모리에 존재하는 IDT(Interrupt Descriptor Table)를 조회하여 해당 system call을 처리하는 handler로 제어를 넘긴다. 이후 system call handler가 system call 번호를 기반으로 system call table을 참조하여 실제 system call 함수를 실행한다.&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;시스템 프로그래밍, 컴퓨터 구조 시간에 배웠던 내용인 것 같은데... 휴학하고 오니까 다 까먹었다... 열심히 해야겠다.&lt;/p&gt;</description>
      <category>CS/운영체제및실습</category>
      <author>PiLove</author>
      <guid isPermaLink="true">https://pi-love0314.tistory.com/36</guid>
      <comments>https://pi-love0314.tistory.com/entry/OS-Week2Operating-System-Overview#entry36comment</comments>
      <pubDate>Tue, 10 Mar 2026 20:41:00 +0900</pubDate>
    </item>
    <item>
      <title>[데이터통신] Week2. Introduction</title>
      <link>https://pi-love0314.tistory.com/entry/DC-Week1-Intrcduction</link>
      <description>&lt;p style=&quot;background-color: #ffffff; color: #252525; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;충남대학교 김기일 교수님, 데이터통신 2주차 정리입니다.&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Data Communcations&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터통신이란, local 또는 remote로 정보를 교환, 공유하는 행위를 말한다. 정보 교환의 주체는 2개 이상의 디바이스이며, 이들은 전송 매체를 통해 정보를 교환한다.&lt;br /&gt;데이터통신 시스템의 유효성은 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Delivery : 시스템은 반드시 데이터를 &lt;b&gt;정확한 목적지에&lt;/b&gt; 전달해야 한다.&lt;/li&gt;
&lt;li&gt;Accuracy : 시스템은 데이터를 &lt;b&gt;손실없이&lt;/b&gt; 정확하게 전달해야 한다.&lt;/li&gt;
&lt;li&gt;Timeliness : 시스템은 데이터를 &lt;b&gt;정해진 시간 내에&lt;/b&gt; 전달해야 한다. 오디오나 비디오의 경우, 데이터가 생성되는 즉시 순서대로 지연없이 전달되는 것을 의미하는데, 이러한 종류의 전달을 &lt;b&gt;실시간 전송(real-time transmission)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;Jitter : Jitter란 오디오나 비디오 패킷을 전송하는 과정에서 &lt;b&gt;지연 시간이 일정하지 않게(uneven) 변하는 현상&lt;/b&gt;을 의미한다. 예를 들어, 비디오 패킷이 30ms 간격으로 전달되어야 할 때 첫 번째 패킷은 30ms에 정상적으로 도착하지만, 두 번째 패킷은 40ms, 그 다음 패킷은 35ms에 도착하는 등 &lt;b&gt;도착 시간이 일정하지 않게 변하는 경우&lt;/b&gt;를 Jitter라고 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1926&quot; data-origin-height=&quot;1144&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AcWyG/dJMcaaka0E0/2AjWjcXKVmUQf5jXT6V7r0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AcWyG/dJMcaaka0E0/2AjWjcXKVmUQf5jXT6V7r0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AcWyG/dJMcaaka0E0/2AjWjcXKVmUQf5jXT6V7r0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAcWyG%2FdJMcaaka0E0%2F2AjWjcXKVmUQf5jXT6V7r0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1926&quot; height=&quot;1144&quot; data-origin-width=&quot;1926&quot; data-origin-height=&quot;1144&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그림을 보면, Jitter를 포함한 데이터 통신과 포함하지 않은 데이터 통신의 차이를 확인할 수 있다. 개발자는 Jitter를 포함한 데이터통신을 사용자가 느끼지 못하도록 만들어야 한다.&lt;br /&gt;Example of problem을 보자. Perfect Stream의 경우에, 데이터가 &quot;ㅁ ㅁ ㅁ ㅁ ㅁ ㅁ&quot; 이런식으로 균등하게 들어오는 반면, Stream with Jitter는 데이터가 &quot;ㅁㅁ&amp;nbsp; &amp;nbsp; &amp;nbsp;ㅁㅁ&amp;nbsp; ㅁ&quot; 이런 식으로 균등하지 않게 들어온다. 또한 예시에서처럼 버퍼가 충분히 할당되지 않은 상황에서 Jitter에 의해 데이터가 한번에 들어오게 되면 오버플로우가 발생할 수 있다.&lt;br /&gt;따라서 개발자는 Stream with Jitter를 사용자가 Perfect Stream으로 체감할 수 있도록 버퍼를 잘 조작해야 한다. 그림의 Playout buffer를 보면 버퍼에 들어오는 데이터를 바로 처리하지 않고, 일정량의 데이터가 차는 경우 처리하는 방식으로 사용자가 Jitter의 발생을 경험하지 않도록 만든다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;743&quot; data-origin-height=&quot;411&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b9uyS2/dJMcabpSp4Z/Mt87atvKYVNndGlhiunQK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b9uyS2/dJMcabpSp4Z/Mt87atvKYVNndGlhiunQK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b9uyS2/dJMcabpSp4Z/Mt87atvKYVNndGlhiunQK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb9uyS2%2FdJMcabpSp4Z%2FMt87atvKYVNndGlhiunQK1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;743&quot; height=&quot;411&quot; data-origin-width=&quot;743&quot; data-origin-height=&quot;411&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;데이터통신은 다음과 같은 구성요소를 가진다. 2개의 디바이스(Sender, Receiver)와 데이터(Message), 데이터를 전달하기 위한 전송 매체(Transmission medium), 그리고 통신에 사용되는 규칙인 프로토콜(Protocol)로 이루어져 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;732&quot; data-origin-height=&quot;467&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kYYz8/dJMcadA7Wfd/VtcoxJ19CJaRrgxke9i0vk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kYYz8/dJMcadA7Wfd/VtcoxJ19CJaRrgxke9i0vk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kYYz8/dJMcadA7Wfd/VtcoxJ19CJaRrgxke9i0vk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkYYz8%2FdJMcadA7Wfd%2FVtcoxJ19CJaRrgxke9i0vk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;732&quot; height=&quot;467&quot; data-origin-width=&quot;732&quot; data-origin-height=&quot;467&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터통신은 데이터가 흐르는 방향에 따라 단방향(Simplex), 반이중(Half-duplex), 전이중(Full-duplex) 통신으로 구분할 수 있다. 반이중 통신은 한쪽에서 데이터를 보내면 반대편에서는 데이터를 보내지 못하는 반면, 전이중 통신은 동시에 데이터를 보낼 수 있다.&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Networks&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;네트워크란, 통신에 사용가능한 디바이스 집합의 연결을 의미한다. 이 집합에는 컴퓨터, 노트북, 핸드폰 등에서부터 데이터의 형태를 변경하는 라우터, 스위치, 모뎀까지 모두 포함된다.&lt;br /&gt;이러한 네트워크를 평가하는 기준은 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Performance : 전송속도, 반응시간, 처리량, 지연시간 등으로 평가&lt;/li&gt;
&lt;li&gt;Reliability : 전송 실패의 빈도, 실패 후 데이터 처리 시간, 고장난 상태에서 네트워크의 견고성 등으로 평가&lt;/li&gt;
&lt;li&gt;Security : 허용되지 않은 접근으로부터 데이터를 보호, 해킹으로부터의 보호, 보안 침해나 손실이 발생했을 때 복구를 위한 절차를 구성하는 것으로 평가&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 평가 기준으로 여러 형태의 네트워크를 살펴보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;711&quot; data-origin-height=&quot;386&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfCCwM/dJMcafFM6Ne/5L4L6KRQmeOWJk6xnW54J1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfCCwM/dJMcafFM6Ne/5L4L6KRQmeOWJk6xnW54J1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfCCwM/dJMcafFM6Ne/5L4L6KRQmeOWJk6xnW54J1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfCCwM%2FdJMcafFM6Ne%2F5L4L6KRQmeOWJk6xnW54J1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;711&quot; height=&quot;386&quot; data-origin-width=&quot;711&quot; data-origin-height=&quot;386&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Performance를 기준으로 보면, a(Point-to-point) 방식은 2개의 디바이스가 직접적으로 데이터를 교환하기 때문에 여러 디바이스가 데이터를 공유하는 방식인 b(Multipoint)보다 빠르다.&lt;br /&gt;Reliability를 기준으로 보면, a는 구조가 단순하기에 고장이 발생할 경우 그 원인을 파악하기 쉽다. 반면 b는 Mainframe에서 고장이 발생할 경우, 다른 여러 디바이스에도 영향을 줄 수 있다.&lt;br /&gt;Security를 기준으로 보면, a는 구조가 단순하여 두 디바이스만 데이터를 공유하기에 데이터가 노출될 가능성이 낮다. 반면 b는 하나의 링크를 여러 디바이스가 공유하므로 다른 디바이스가 데이터에 접근할 가능성이 높다.&lt;br /&gt;그렇다면, b는 대체 왜 쓸까? 그림에서 a 네트워크의 디바이스 개수를 늘려보자. Link의 개수가 매우 늘어날 것이다. 반면에 b는 여전히 하나의 Link만 사용한다. 즉, 비용적인 측면에서 b가 월등히 좋다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;753&quot; data-origin-height=&quot;384&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bLikKy/dJMcafMz1d5/kDGoyI7kj5Rb82blAOcVw1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bLikKy/dJMcafMz1d5/kDGoyI7kj5Rb82blAOcVw1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bLikKy/dJMcafMz1d5/kDGoyI7kj5Rb82blAOcVw1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbLikKy%2FdJMcafMz1d5%2FkDGoyI7kj5Rb82blAOcVw1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;753&quot; height=&quot;384&quot; data-origin-width=&quot;753&quot; data-origin-height=&quot;384&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;a 네트워크의 디바이스 개수를 5로 늘리면 다음과 같아진다. 디바이스 개수를 n이라고 하면, Link의 개수는 n(n-1)/2가 된다. 이러한 네트워크 구조를 mesh topology라고 부른다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;595&quot; data-origin-height=&quot;357&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wsTFh/dJMcagkntxB/JFvfkZxzQk4pHgrkfTxf80/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wsTFh/dJMcagkntxB/JFvfkZxzQk4pHgrkfTxf80/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wsTFh/dJMcagkntxB/JFvfkZxzQk4pHgrkfTxf80/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwsTFh%2FdJMcagkntxB%2FJFvfkZxzQk4pHgrkfTxf80%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;595&quot; height=&quot;357&quot; data-origin-width=&quot;595&quot; data-origin-height=&quot;357&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나의 Hub를 여러 대의 디바이스가 공유하는 형태이다. Performance 측면에서도, Security 측면에서도 Point-to-point 방식과 비슷한 점수를 줄 수 있다. 그러나, Reliability를 따져보자. Hub가 고장나게 되면, 다른 모든 디바이스에 영향을 주기 때문에 네트워크의 견고성이 부족하다고 할 수 있다. 이러한 형태의 네트워크를 Star topology라고 한다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;725&quot; data-origin-height=&quot;219&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/djLWbv/dJMcah4F44q/WEJrxtBLWaWi3BHSDtOD21/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/djLWbv/dJMcah4F44q/WEJrxtBLWaWi3BHSDtOD21/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/djLWbv/dJMcah4F44q/WEJrxtBLWaWi3BHSDtOD21/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdjLWbv%2FdJMcah4F44q%2FWEJrxtBLWaWi3BHSDtOD21%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;725&quot; height=&quot;219&quot; data-origin-width=&quot;725&quot; data-origin-height=&quot;219&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에 봤던 b 와 동일한 네트워크 형태이다. Performace, Reliabitlity, Security 모두 좋지 않지만, 비용적인 측면에서 만큼은 매우 좋다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;754&quot; data-origin-height=&quot;300&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bCWO3r/dJMcabDox8P/TvradV4Tobt1vXiDuunfk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bCWO3r/dJMcabDox8P/TvradV4Tobt1vXiDuunfk1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bCWO3r/dJMcabDox8P/TvradV4Tobt1vXiDuunfk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbCWO3r%2FdJMcabDox8P%2FTvradV4Tobt1vXiDuunfk1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;754&quot; height=&quot;300&quot; data-origin-width=&quot;754&quot; data-origin-height=&quot;300&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Bus topology에서 cable의 끝과 끝을 연결한 형태이다. 솔직히 이렇게 해서 뭐가 달라지는 지 잘 모르겠다.&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Network Types&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 네트워크의 형태에 따라 물리적 구조(topology)를 결정했다면, 이번에는 네트워크의 크기, 지리적 범위 등을 고려하여 종류를 구분해보자.&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;LAN(Local Area Networks)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;교실, 집, 캠퍼스 정도의 크기에서 주로 사용되는 네트워크이다.&amp;nbsp;&lt;br /&gt;LAN 내에 있는 PC, 프린터, 핸드폰 등의 호스트는 identifier(식별자) 즉, address(주소)를 가지며, 이 address는 LAN 내에서 해당 호스트를 고유하게 구별한다. 참고로, LAN에서는 이 identifier로 MAC Address를 사용하고, WAN에서는 IP를 사용한다고 한다. 아마 이건 다음 시간에 더 자세히 알아보지 않을까 싶당.&lt;br /&gt;LAN 내에서 한 호스트에서 다른 호스트로 데이터를 보낼 때, Source address(출발지 주소)와 Destination address(도착지 주소)가 모두 포함된다. 추가로 Destination address가 잘못 도착했을 때, 이 정보를 이용하여 개발자가 지정한 프로토콜에 따라 데이터를 삭제하는 등의 방식으로 처리할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;663&quot; data-origin-height=&quot;468&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UJwPR/dJMcajaiZaL/x1VzJ8TdzzmTquJfyPa4nk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UJwPR/dJMcajaiZaL/x1VzJ8TdzzmTquJfyPa4nk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UJwPR/dJMcajaiZaL/x1VzJ8TdzzmTquJfyPa4nk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUJwPR%2FdJMcajaiZaL%2Fx1VzJ8TdzzmTquJfyPa4nk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;663&quot; height=&quot;468&quot; data-origin-width=&quot;663&quot; data-origin-height=&quot;468&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;WAN(Wide Area Network)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도시, 주, 심지어 국가 단위까지 사용 가능한 네트워크이다.&lt;br /&gt;LAN은 보통 호스트들을 서로 연결하는 반면에, WAN은 &lt;b&gt;Switch, Router, Modem&lt;/b&gt; 등의 연결장치(Connecting device)를 연결한다. 또한 LAN은 일반적으로 이를 사용하는 조직이 개인적으로 소유하지만, WAN은 보통 통신 회사가 구축하고 운영하며, 이를 사용하는 조직이 임대하여 사용한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;626&quot; data-origin-height=&quot;456&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LMtHW/dJMcajg4gWQ/kkt7asGofPlOeKkeIWQrM0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LMtHW/dJMcajg4gWQ/kkt7asGofPlOeKkeIWQrM0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LMtHW/dJMcajg4gWQ/kkt7asGofPlOeKkeIWQrM0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLMtHW%2FdJMcajg4gWQ%2Fkkt7asGofPlOeKkeIWQrM0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;626&quot; height=&quot;456&quot; data-origin-width=&quot;626&quot; data-origin-height=&quot;456&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;WAN 내부에 여러개의 switch가 있는 경우, 다음과 같은 형태로 네트워크를 디자인한다. 여러 LAN 네트워크를 서로 연결한다는 측면에서 성능, 신뢰성, 보안 모두 중요하기 때문에 Mesh topology 를 사용하여 디자인 하는 것이 효율적이다.&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Internet History&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Standards&lt;/h2&gt;</description>
      <category>CS/데이터통신</category>
      <author>PiLove</author>
      <guid isPermaLink="true">https://pi-love0314.tistory.com/35</guid>
      <comments>https://pi-love0314.tistory.com/entry/DC-Week1-Intrcduction#entry35comment</comments>
      <pubDate>Tue, 10 Mar 2026 00:03:57 +0900</pubDate>
    </item>
    <item>
      <title>[모각코] 회고</title>
      <link>https://pi-love0314.tistory.com/entry/%EB%AA%A8%EA%B0%81%EC%BD%94-%ED%9A%8C%EA%B3%A0</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;시간이 흘러 어느덧 개강을 앞두고 있다. 25년 12월 말에 시작한 모각코도 저번주 금요일을 마지막으로 종료되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음 시작을 돌이켜보면 정말 이유없이 의기양양했던 것 같다. '개강 전에 공부 좀 하면 좋지 않을까?' 하는 단순한 마음가짐과 함께 친구들을 모았고 그렇게 시작했었다. 목표는 ADP 필기 시험 합격이였다. 이렇게 동기는 약한데 목표는 높게 잡으니 내 목표에 맞게 계획을 수립하는 것과 그 계획을 따라가는 게 매우 힘들었다. 자격증 자체도 정보가 많지 않아 하나하나 찾아가며 계획을 수정하고 정말 힘들었다... 알바를 병행하면서 공부를 하는 것도 처음이라 더더욱 그랬다. 그렇게 2주차까지는 열심히 공부했지만, 공부해야하는 양도 너무 방대했고, 알바하고 오면 몸이 너무 지쳐서 쉬는 일들이 발생하는 바람에 눈덩이처럼 해야하는 숙제가 늘어갔다. 결국 처음 계획으로 했던 ADP 필기를 포기하게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3주차부터는 ADP 대신 토익 공부를 목표로 세웠다. 토익 공부는 계획을 너무 촘촘하게 짜지는 않았다. 2주차까지 세웠었던 미련하고 무식한 계획 덕분에 내가 알바와 공부를 병행하면서 버틸 수 있는 스트레스가 어느정도인지 대충 알았기 때문이다. 계획을 너무 구체적으로 세분화하기 보다는 일주일 단위로 총 해야하는 공부량을 정해서 진행했다. 덕분에 토익 준비는 나쁘지 않게 한 기분이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 모각코에 대해서는 좀 아쉬운 점이 많았다. 내가 모은 팀원들인데, 시작하고 2주만에 먼저 지쳐서 팀원들에게 큰 신경을 써주지 못한 느낌이다. 또한 팀원들이 서로 어색해보였는데, 이 부분도 노력했지만 잘 해소가 되지 않은 것 같다. 결국 팀원들도 하나 둘 지쳐서 어느순간부터는 결석을 많이 하게 되는 것 같았다... '모각코'라는 단어가 '모여서 각자 코딩'이란 뜻이고 서로 공부하는 내용도 다르지만, 결국 팀 단위로 진행하는 것이기 때문에 팀원들과의 소통 부분에서 너무나 아쉬운 것 같다.&lt;/p&gt;</description>
      <category>모각코</category>
      <author>PiLove</author>
      <guid isPermaLink="true">https://pi-love0314.tistory.com/34</guid>
      <comments>https://pi-love0314.tistory.com/entry/%EB%AA%A8%EA%B0%81%EC%BD%94-%ED%9A%8C%EA%B3%A0#entry34comment</comments>
      <pubDate>Sun, 22 Feb 2026 22:03:20 +0900</pubDate>
    </item>
    <item>
      <title>[모각코 - 5, 6회차] 토익</title>
      <link>https://pi-love0314.tistory.com/entry/%EB%AA%A8%EA%B0%81%EC%BD%94-5-6%ED%9A%8C%EC%B0%A8-%ED%86%A0%EC%9D%B5</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;5회차까지 토익 기출 보카를 Day1~5까지 외웠다. 그리고 750+ 교재의 LC 파트를 한번 빠르게 훑었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6회차에는 토익 기출 보카를 Day6~10까지 외웠다. 그리고 750+ 교재의 RC 파트를 한번 빠르게 훑었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시험날은 2월 28일로 잡았으며, 남은 기간 동안 기출 보카는 끝까지 외우고 빠르게 2회독을 할 예정이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;750+교재는 2월 20일까지 다시 한번 2회독을 하는 것을 목표로 하고, 일주일 동안은 실전 기출문제를 풀어볼 예정이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;부끄럽지만, 과거에 1~2주 정도 준비하고 본 토익 점수가 595점이였는데, 이번에는 좀 더 열심히 준비해볼 예정이다.&lt;/p&gt;</description>
      <author>PiLove</author>
      <guid isPermaLink="true">https://pi-love0314.tistory.com/33</guid>
      <comments>https://pi-love0314.tistory.com/entry/%EB%AA%A8%EA%B0%81%EC%BD%94-5-6%ED%9A%8C%EC%B0%A8-%ED%86%A0%EC%9D%B5#entry33comment</comments>
      <pubDate>Fri, 13 Feb 2026 21:44:18 +0900</pubDate>
    </item>
    <item>
      <title>[모각코-4회차] ADP 포기...</title>
      <link>https://pi-love0314.tistory.com/entry/%EB%AA%A8%EA%B0%81%EC%BD%94-4%ED%9A%8C%EC%B0%A8-ADP-%ED%8F%AC%EA%B8%B0</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;모각코 4회차에는 방학 계획을 좀 수정하게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존 목표는 ADP 필기 합격이였지만, 주어진 시간을 생각했을 때 쉽지 않을 것이라고 판단되어 결국 포기하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알바와 다른 공부와 병행하다보니, 선택과 집중이 필요했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 모각코 시간에 ADP 공부가 아닌, 토익을 준비하기로 결정했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4회차에는 남은 방학 기간동안 토익을 준비하기 위해 간단한 계획을 정리하였다.&lt;/p&gt;</description>
      <category>모각코</category>
      <author>PiLove</author>
      <guid isPermaLink="true">https://pi-love0314.tistory.com/32</guid>
      <comments>https://pi-love0314.tistory.com/entry/%EB%AA%A8%EA%B0%81%EC%BD%94-4%ED%9A%8C%EC%B0%A8-ADP-%ED%8F%AC%EA%B8%B0#entry32comment</comments>
      <pubDate>Fri, 13 Feb 2026 21:39:37 +0900</pubDate>
    </item>
    <item>
      <title>[모각코-2, 3회차] 2과목 2장 정리</title>
      <link>https://pi-love0314.tistory.com/entry/%EB%AA%A8%EA%B0%81%EC%BD%94-2-3%ED%9A%8C%EC%B0%A8-2%EA%B3%BC%EB%AA%A9-2%EC%9E%A5-%EC%A0%95%EB%A6%AC</link>
      <description>&lt;p&gt;&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignCenter&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/8MNH5/dJMcacIGey7/u5KlZu1jPJHk9nTgbhqSL1/2%EA%B3%BC%EB%AA%A9%202%EC%9E%A5%20%EC%A0%95%EB%A6%AC.pptx?attach=1&amp;amp;knm=tfile.pptx&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;2과목 2장 정리.pptx&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;2.73MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <author>PiLove</author>
      <guid isPermaLink="true">https://pi-love0314.tistory.com/31</guid>
      <comments>https://pi-love0314.tistory.com/entry/%EB%AA%A8%EA%B0%81%EC%BD%94-2-3%ED%9A%8C%EC%B0%A8-2%EA%B3%BC%EB%AA%A9-2%EC%9E%A5-%EC%A0%95%EB%A6%AC#entry31comment</comments>
      <pubDate>Fri, 23 Jan 2026 20:08:27 +0900</pubDate>
    </item>
    <item>
      <title>[모각코-1회차] 2과목 1장 정리</title>
      <link>https://pi-love0314.tistory.com/entry/2%EA%B3%BC%EB%AA%A9-1%EC%9E%A5-%EC%A0%95%EB%A6%AC</link>
      <description>&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. ETL&lt;/h3&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터의 이동 및 변환 절차와 관련된 용어로, ODS &amp;gt; DWH &amp;gt; DM 에 데이터를 적재하는 과정에 사용됨&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;용어 그대로 데이터 원천(Source)로부터 데이터를 추출(Extraction)하고 변형(Transformation)하여 적재(Load)하는 기능을 수행&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1-1. 데이터가 DW에 적재되기까지 과정&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1089&quot; data-origin-height=&quot;788&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/clzptR/dJMcaivaJPd/4l2g9tlsKK6SvukL9Mxgi0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/clzptR/dJMcaivaJPd/4l2g9tlsKK6SvukL9Mxgi0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/clzptR/dJMcaivaJPd/4l2g9tlsKK6SvukL9Mxgi0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FclzptR%2FdJMcaivaJPd%2F4l2g9tlsKK6SvukL9Mxgi0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;489&quot; height=&quot;788&quot; data-origin-width=&quot;1089&quot; data-origin-height=&quot;788&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;Interface&lt;/b&gt;&lt;br /&gt;다양한 원천으로부터 데이터를 획득하기 위한 매커니즘 구현&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Staging ETL&lt;/b&gt;&lt;br /&gt;획득한 데이터를 스테이징 테이블에 임시로 저장&lt;br /&gt;임시로 저장하는 이유는 ODS에 데이터를 적재하기 전 수집한 데이터에 대해 전처리를 해야하기 때문에 원본 그대로의 데이터를 백업으로 저장&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Profiling ETL&lt;/b&gt;&lt;br /&gt;스테이징 테이블의 데이터 품질 측정&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Cleansing ETL&lt;/b&gt;&lt;br /&gt;다양한 규칙을 적용하여 데이터의 보정 작업 수행&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Integration ETL&lt;/b&gt;&lt;br /&gt;다양한 원천으로부터의 데이터를 통합&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Denormalizing ETL&lt;/b&gt;&lt;br /&gt;DW 또는 DM에 데이터를 적재하기 위해 데이터에 대해 비정규화 수행&lt;/li&gt;
&lt;/ol&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. ODS, DW&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2-0. ODS&lt;/h4&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터에 대한 추가 작업을 위해 다양한 원천(Source)로부터 수집한 데이터를 통합한 데이터베이스&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ODS는 DW로 적재하기 이전 단계의 데이터베이스로, 실시간 또는 근접 실시간 간격으로 데이터를 업데이트하기에 실시간 조회가 가능함. 데이터를 업데이트하는 과정에서는 일반적인 데이터 클렌징, 중복제거, 무결성 점검 등의 작업을 수행함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ODS는 DW로 데이터를 적재하기 이전 단계의 데이터베이스인데, DW에서는 데이터를 일괄적(Batch 단위)으로 업데이트하므로 실시간 조회가 쉽지 않음. 따라서 ODS는 원천 시스템과 DW 사이의 &quot;대기 공간&quot;과 같은 개념임.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2-1. ODS의 구성단계&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1182&quot; data-origin-height=&quot;722&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pMdE8/dJMcai9LVyA/b3TinjNMsPoZhnKExQR3DK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pMdE8/dJMcai9LVyA/b3TinjNMsPoZhnKExQR3DK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pMdE8/dJMcai9LVyA/b3TinjNMsPoZhnKExQR3DK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpMdE8%2FdJMcai9LVyA%2Fb3TinjNMsPoZhnKExQR3DK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;470&quot; height=&quot;287&quot; data-origin-width=&quot;1182&quot; data-origin-height=&quot;722&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;Interface layer&lt;/b&gt;&lt;br /&gt;다양한 데이터 원천으로부터 데이터를 획득하는 단계&lt;br /&gt;데이터 획득을 위한 프로토콜로 OLEDB, ODBC, FTP 등이 사용됨&lt;br /&gt;DW에 대한 실시간 또는 근접 실시간 OLAP 질의를 지원하기 위한 실시간 데이터 복제 인터페이스 기술에 함께 활용됨&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Staging layer&lt;/b&gt;&lt;br /&gt;원천으로부터 추출한 데이터를 하나 이상의 스테이징 테이블에 저장하는 단계&lt;br /&gt;스테이징 테이블은 정규화가 배제되며, 스키마는 데이터 원천의 구조에 의존적임&lt;br /&gt;데이터 원천과 스테이징 테이블 사이의 데이터 매핑은 일대일 또는 일대다로 구성됨&lt;br /&gt;적재 타임스탬프, 값에 대한 체크 섬 등의 통제 정보들이 추가됨&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Profiling layer&lt;/b&gt;&lt;br /&gt;범위/도메인/유일성 확보 등의 규칙을 기준으로 데이터 품질을 점검하는 단계&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Cleansing layer&lt;/b&gt;&lt;br /&gt;프로파일링 단계에서 식별된 오류 데이터들을 수정하는 단계&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Integration layer&lt;/b&gt;&lt;br /&gt;수정 완료한 데이터를 ODS 내의 단일 통합 테이블에 적재하는 단계&lt;br /&gt;이 단계 이전의 데이터들은 다양한 원천으로부터 가져온 데이터이므로 서로 다른 테이블에 저장되어 있을 수 있음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Export layer&lt;/b&gt;&lt;br /&gt;앞 단계에서 통합된 데이터에 대해 보안 규칙을 반영한 ETL을 수행하여 익스포트 테이블을 생성하고 다양한 DBMS 클라이언트, DM, DW에 해당 테이블을 적재하는 단계&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2-2. DW&lt;/h4&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ODS를 통해 정제 및 통합된 데이터가 데이터 분석과 보고서 생성을 위해 적재되는 데이터 저장소&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DW가 필요한 이유는 원천으로부터 데이터를 분석하고 사용하려면, 기존의 서비스가 느려질 가능성이 있고, 다양한 원천으로부터 통합된 데이터베이스를 구축함으로써, 일괄적으로 데이터를 관리할 수 있기 때문임.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2-3. DW의 특징&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;주제 중심성(Subject Oriented)&lt;/b&gt;&lt;br /&gt;다양한 원천으로부터 얻은 데이터들은 각각의 주제를 중심으로 테이블이 생성됨&lt;/li&gt;
&lt;li&gt;&lt;b&gt;영속성/비휘발성(Non Volatile)&lt;/b&gt;&lt;br /&gt;DW의 데이터는 최초 저장 이후 Read Only 속성을 가짐&lt;/li&gt;
&lt;li&gt;&lt;b&gt;통합성(Integrated)&lt;/b&gt;&lt;br /&gt;다양한 원천으로부터 생성된 데이터들의 통합본&lt;/li&gt;
&lt;li&gt;&lt;b&gt;시계열성(Time Variant)&lt;/b&gt;&lt;br /&gt;시간 순에 의한 이력 데이터들의 기록들이 저장되어 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2-4. DW의 테이블 모델링 기법&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;632&quot; data-origin-height=&quot;622&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/djCXNf/dJMcadgkz5B/ZSZXe7DK46MY2pnLE6XWK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/djCXNf/dJMcadgkz5B/ZSZXe7DK46MY2pnLE6XWK0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/djCXNf/dJMcadgkz5B/ZSZXe7DK46MY2pnLE6XWK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdjCXNf%2FdJMcadgkz5B%2FZSZXe7DK46MY2pnLE6XWK0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;336&quot; height=&quot;622&quot; data-origin-width=&quot;632&quot; data-origin-height=&quot;622&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;스타 스키마(조인 스키마)&lt;/b&gt;&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;단일 사실 테이블(Fact Table)을 중심으로 다수의 차원 테이블(Dimenstion Table)로 구성됨&lt;/li&gt;
&lt;li&gt;전통적 관계형 데이터베이스를 통해 다차원 데이터베이스 기능을 구현할 수 있음&lt;/li&gt;
&lt;li&gt;사실 테이블은 보통 제 3정규형으로 모델링됨&lt;/li&gt;
&lt;li&gt;차원 테이블은 보통 비정규화된 제 2정규형으로 모델링됨&lt;/li&gt;
&lt;li&gt;복잡도가 낮아 쿼리 작성이 용이하지만 차원 테이블들의 비정규화에 따른 데이터 중복으로 인해 데이터 적재에 상대적으로 많은 시간이 소요됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;886&quot; data-origin-height=&quot;657&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/k7slS/dJMcahpyql6/1ovSrEUt6wW6ujKAKvoOG0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/k7slS/dJMcahpyql6/1ovSrEUt6wW6ujKAKvoOG0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/k7slS/dJMcahpyql6/1ovSrEUt6wW6ujKAKvoOG0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fk7slS%2FdJMcahpyql6%2F1ovSrEUt6wW6ujKAKvoOG0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;448&quot; height=&quot;332&quot; data-origin-width=&quot;886&quot; data-origin-height=&quot;657&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;스노우 플레이크 스키마&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스타 스키마의 차원 테이블을제 3정규형으로 모델링한 형태&lt;/li&gt;
&lt;li&gt;데이터의 중복이 제거되어 데이터 적재 시 시간이 단축되지만, 복잡성의 증가로 조인 테이블 개수가 증가하고 쿼리 작성 난이도가 상승함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. CDC&lt;/h3&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CDC(Change Data Capute)는 용어 그대로 데이터베이스 내 데이터에 대한 변경을 식별하여 필요한 후속처리를 자도오하하는 기술 또는 설계 기법이자 구조를 말함&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3-1. CDC 구현 기법&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Time Stamp on Rows&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Version Numbers on Rows&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Status on Rows&lt;br /&gt;&lt;/b&gt;타임스탬프 및 버전넘버에 대한 보완 용도로, 변경 여부를 True/False 값으로 저장하는 상태 기반 변경 여부 판단 기법&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Triggers on Tables&lt;br /&gt;&lt;/b&gt;데이터베이스 내 트리거를 활용하여 데이터 변경 내역을 별도의 테이블에 기록하는 기법&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Event Programming&lt;/b&gt;&lt;br /&gt;데이터 변경 식별 기능을 application에 구현하여 다양한 조건에 의한 CDC 매커니즘을 구현하는 기법&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;b&gt;Log Scanner on Database&lt;br /&gt;&lt;/b&gt;&lt;/b&gt;모든 데이터베이스는 장애 복구를 위해 데이터에 발생하는 모든 변화를 로그 파일에 기록하는데, 이 로그에 대한 스캐닝 및 변경 내역을 확인하여 CDC 매커니즘을 구현하는 기법&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3-2. CDC 구현 방식&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Push 방식&lt;/b&gt;&lt;br /&gt;원천에서 변경을 식별하고 대상 시스템에 변경 데이터를 적재&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Pull 방식&lt;/b&gt;&lt;br /&gt;대상 시스템에서 원천을 정기적으로 살펴보고 필요 시 데이터를 다운&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. EAI&lt;/h3&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기업 내 각종 애플리케이션 간의 상호 연동이 가능하도록 통합하는 솔루션으로, 상호 이질적인 정보 시스템들의 데이터를 연계함으로써 상호 융화 내지 동기화 되도록 만듦&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비즈니스 프로세스를 자동화하고 실시간으로 통합 연계가 가능하게 할 수 있음. 즉, EAI는 실시간 혹은 근접 실시간의 처리가 가능함.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4-1. EAI의 구성요소&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;어댑터(Adapter)&lt;/b&gt;&lt;br /&gt;각 정보 시스템과 EAI 허브 간의 연결성 확보&lt;/li&gt;
&lt;li&gt;&lt;b&gt;버스(Bus)&lt;/b&gt;&lt;br /&gt;어댑터를 매개로 연결된 각 정보 시스템들 간의 데이터 연동 경로&lt;/li&gt;
&lt;li&gt;&lt;b&gt;브로커(Broker)&lt;/b&gt;&lt;br /&gt;데이터 연동 규칙 통제&lt;/li&gt;
&lt;li&gt;&lt;b&gt;트랜스포머(Transformer)&lt;/b&gt;&lt;br /&gt;데이터 형식 변환 담당&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4-2. EAI 데이터 연계 방식&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1071&quot; data-origin-height=&quot;462&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cYWy8o/dJMcaiPtooe/i6EueQpW3fdisFh2Q4gwhk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cYWy8o/dJMcaiPtooe/i6EueQpW3fdisFh2Q4gwhk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cYWy8o/dJMcaiPtooe/i6EueQpW3fdisFh2Q4gwhk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcYWy8o%2FdJMcaiPtooe%2Fi6EueQpW3fdisFh2Q4gwhk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;670&quot; height=&quot;289&quot; data-origin-width=&quot;1071&quot; data-origin-height=&quot;462&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;기존의 데이터 연계 방식 : Point to Point&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;정보 시스템 간의 데이터를 1대1로 연계함으로써 그림과 같은 복잡성이 발생&lt;/li&gt;
&lt;li&gt;N개의 연결 대상 노드들이 존재할 경우, 연결은 N(N-1)/2개가 됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;EAI의 데이터 연계 방식 : Hub and Spoke&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;가운데 지점에 허브 역할을 하는 브로커를 두고, 연결 대상 노드들의 데이터 연계 요구를 중계&lt;/li&gt;
&lt;li&gt;다수 정보 시스템의 데이터를 중앙의 Hub가 연계하고 통합&lt;/li&gt;
&lt;li&gt;각 연결의 대상이 되는 노드들이 Spoke에 해당&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4-3. EAI 구현 유형&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Mediation(Intra-Communication)&lt;/b&gt;&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;EAI 엔진이 브로커로 동작하며, 특정 정보 시스템 내의 데이터 생성, 갱신, 커밋 등의 이벤트 발생을 식별하고 미리 약속된 정보 시스템에 해당 내용을 전달&lt;/li&gt;
&lt;li&gt;Publish/Subscribe model이라고 부름&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Federation(Inter Communication)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;EAI 엔진이 외부 정보 시스템으로부터 데이터 요청들을 일괄적으로 수령하여 필요한 데이터를 각각의 정보 시스템에 전달&lt;/li&gt;
&lt;li&gt;Request/Reply model이라고 부름&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;4-4. EAI vs ESB&lt;/h4&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 110px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 22px;&quot;&gt;
&lt;td style=&quot;width: 9.84493%; height: 22px; text-align: center;&quot;&gt;구분&lt;/td&gt;
&lt;td style=&quot;width: 42.403%; height: 22px; text-align: center;&quot;&gt;EAI&lt;br /&gt;(Enterprise Application Integration)&lt;/td&gt;
&lt;td style=&quot;width: 47.752%; height: 22px; text-align: center;&quot;&gt;ESB&lt;br /&gt;(Enterprise Service Bus)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 22px;&quot;&gt;
&lt;td style=&quot;width: 9.84493%; height: 22px; text-align: center;&quot;&gt;기능&lt;/td&gt;
&lt;td style=&quot;width: 42.403%; height: 22px; text-align: center;&quot;&gt;미들웨어(Hub)를 이용하여 비즈니스 로직을 중심으로 &lt;br /&gt;Application을 통합&amp;middot;연계&lt;/td&gt;
&lt;td style=&quot;width: 47.752%; height: 22px; text-align: center;&quot;&gt;미들웨어(Bus)를 이용하여 서비스 중심으로 시스템을 &lt;br /&gt;유기적으로 연계&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 22px;&quot;&gt;
&lt;td style=&quot;width: 9.84493%; height: 22px; text-align: center;&quot;&gt;통합관점&lt;/td&gt;
&lt;td style=&quot;width: 42.403%; height: 22px; text-align: center;&quot;&gt;Application&lt;/td&gt;
&lt;td style=&quot;width: 47.752%; height: 22px; text-align: center;&quot;&gt;Process&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 22px;&quot;&gt;
&lt;td style=&quot;width: 9.84493%; height: 22px; text-align: center;&quot;&gt;로직연동&lt;/td&gt;
&lt;td style=&quot;width: 42.403%; height: 22px; text-align: center;&quot;&gt;개별 Application에서 수행&lt;/td&gt;
&lt;td style=&quot;width: 47.752%; height: 22px; text-align: center;&quot;&gt;ESB에서 수행&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 22px;&quot;&gt;
&lt;td style=&quot;width: 9.84493%; height: 22px; text-align: center;&quot;&gt;아키텍처&lt;/td&gt;
&lt;td style=&quot;width: 42.403%; height: 22px; text-align: center;&quot;&gt;단일 접점인 허브시스템을 이용한 중앙집중식 연결구조&lt;/td&gt;
&lt;td style=&quot;width: 47.752%; height: 22px; text-align: center;&quot;&gt;버스(Bus) 형태의 느슨하고 유연한 연결구조&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5. 대용량 비정형 데이터 처리방법&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;대용량 로그 데이터 수집
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;로그(Log)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기업에서 발생하는 대표적인 비정형 데이터&lt;/li&gt;
&lt;li&gt;로그 데이터 수집 시스템 예 : 아파리 Flume-NG, 페이스북 Scribe, 아파치 Chuckwa 등&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;대용량 비정형 데이터 수집 시스템의 특징&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;초고석 수집 성능과 확장성&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데이터 전송 보장 매커니즘&lt;/b&gt;&lt;b&gt;&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터가 전송 중간에 끊기지 않도록 보장할 수 있는 매커니즘이 필요&lt;/li&gt;
&lt;li&gt;여러 단계를 거쳐 저장소에 도착할 때 인접한 단계끼리 신호를 주고받아 이벤트 유실을 방지하는 방식으로 전송을 보장할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;다양한 수집과 저장 플러그인&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;수집하는 중에 오류가 발생하는 경우를 대비하여 저장 플러그인을 미리 구현&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;인터페이스 상속을 통합 애플리케이션 기능 확장&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;다양한 원천으로부터 데이터를 수집하기 때문에, 공통적인 내용은 인터페이스 상속을 통해 구현&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;수집한 대규모 데이터에 대한 대규모 분산 병렬 처리&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;하둡(Hadoop)&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;5-1. 하둡(Hadoop)&lt;/h4&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대규모 분산 병렬 처리의 업계 표준인 맵리듀스(MapReduce)와 분산 파일시스템인(HDFS)를 핵심 구성요소로 가지는 플랫폼 기술로, 여러 대의 컴퓨터를 마치 하나의 시스템인 것처럼 묶어 분산 환경에서 빅데이터를 저장 및 처리할 수 있도록 하는 자바 기반의 오픈소스 프레임워크&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하둡은 비공유 분산 아키텍처를 사용함&lt;br /&gt;비공유 분산 아키텍처란, 분산 환경에서 각각의 컴퓨터(노드)들이 독립적인 CPU, 메모리, 로컬 디스크를 가지는 구조를 말함&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;5-2. 하둡의 특징&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;선형적인 성능과 용량 확장
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;비공유 분산 아키텍처 시스템이므로 서버를 추가하면 연산 기능과 저장 기능이 서버의 대수에 비례하여 선형적으로 증가함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;고장 감내성
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;분산 파일시스템(HDFS)에 저장되는 데이터는 3중복제 되어 서로 다른 물리서버에 저장되므로 데이터 유실을 방지함&lt;/li&gt;
&lt;li&gt;분산 병렬 처리(MapReduce) 작업 수행 중 특정 태스크에 장애가 발생하면, 해당 태스크만 다른 서버에서 재실행&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;핵심 비즈니스 로직에 집중
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;하둡의 맵리듀스는 맵과 리듀스라는 2개의 함수만 구현하면서 동작하는 시스템&lt;/li&gt;
&lt;li&gt;알고리즘 및 로직 개발자는 맵리듀스라는 분산 병렬 처리 시스템의 데이터 처리/분석 방식만 이해하고 비즈니스 목적에 맞게 코드만 작성하면됨&lt;/li&gt;
&lt;li&gt;시스템 수준에서 발생하는 장애에 대한 자동복구를 제공하고, 확정성 및 성능 등의 이슈도 하둡이 내부적으로 최적화하여 처리함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;하둡 에코 시스템
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;하둡 프레임워크를 이루고 있는 다양한 서브 프로젝트들의 집합으로 수집, 저장, 처리기술과 분석, 실시간 SQL 질의 기술로 구분됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;5-3. 하둡 에코 시스템&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1304&quot; data-origin-height=&quot;686&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cefsEc/dJMcabQodxq/lx7IJ5KvFPoZBygvH4bt6K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cefsEc/dJMcabQodxq/lx7IJ5KvFPoZBygvH4bt6K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cefsEc/dJMcabQodxq/lx7IJ5KvFPoZBygvH4bt6K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcefsEc%2FdJMcabQodxq%2Flx7IJ5KvFPoZBygvH4bt6K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1304&quot; height=&quot;686&quot; data-origin-width=&quot;1304&quot; data-origin-height=&quot;686&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;비정형 데이터 수집 : Chuckwa, Flume, Scribe&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Chuckwa : 분산된 각 서버에서 에이전트를 실행하고, 컬렉터가 에이전트로부터 데이터를 받아와 HDFS에 저장하는 기술&lt;/li&gt;
&lt;li&gt;Flume : 많은 양의 로그 데이터를 효율적으로 수집하기 위해 이벤트와 에이전트를 활용하는 기술&lt;/li&gt;
&lt;li&gt;Scribe : 다수의 서버에서 실시간 스트리밍되는 로그 데이터를 수집하여 분산 시스템에 저장하는 대용량 실시간 수집 기술&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;정형 데이터 수집 : Sqoop, Hiho&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Sqoop : 대용량 데이터 전송 솔루션으로 RDBMS에서 HDFS로 데이터를 수집하거나(Import),&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; HDFS에서 RDBMS로 데이터를 보내는(Export) 기술&lt;/li&gt;
&lt;li&gt;Hiho : Sqoop과 같은 대용량 데이터 전송 솔루션으로, HDFS에서 데이터를 가져오기 위한 SQL을 지정할 수 있고&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;JDBC 인터페이스 지원&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;분산 데이터 저장 : HDFS&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;대용량 파일을 분산된 서버에 저장하고, 그 데이터를 빠르게 처리할 수 있게 하는 하둡 분산 파일시스템으로, 범용 하드웨어 기반 클러스터에서 실행되고 데이터 접근 패턴을 스트리밍 방식으로 지원하며, 다중복제, 대용량 파일 저장, 온라인 변경, 범용서버 기반, 자동복구 특징이 있음&lt;/li&gt;
&lt;li&gt;네임노드, 보조 네임노드, 데이터 노드로 이루어짐&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 132px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 22px;&quot;&gt;
&lt;td style=&quot;width: 13.3721%; text-align: center; height: 22px;&quot;&gt;구 성&lt;/td&gt;
&lt;td style=&quot;width: 86.6279%; text-align: center; height: 22px;&quot;&gt;특 징&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 66px;&quot;&gt;
&lt;td style=&quot;width: 13.3721%; text-align: center; height: 66px;&quot;&gt;네임노드&lt;/td&gt;
&lt;td style=&quot;width: 86.6279%; text-align: left; height: 66px;&quot;&gt;마스터 역할&lt;br /&gt;모든 메타데이터 관리&lt;br /&gt;데이터 노드들로부터 하트비트를 받아 상태 체크&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 22px;&quot;&gt;
&lt;td style=&quot;width: 13.3721%; text-align: center; height: 22px;&quot;&gt;보조 네임노드&lt;/td&gt;
&lt;td style=&quot;width: 86.6279%; text-align: left; height: 22px;&quot;&gt;상태 모니터링을 보조&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 22px;&quot;&gt;
&lt;td style=&quot;width: 13.3721%; text-align: center; height: 22px;&quot;&gt;데이터노드&lt;/td&gt;
&lt;td style=&quot;width: 86.6279%; text-align: left; height: 22px;&quot;&gt;슬레이브 역할&lt;br /&gt;데이터 입출력 요청&lt;br /&gt;데이터 유실방지를 위해 블록을 3층 복&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;분산 데이터베이스 : HBase&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HDFS를 기반으로 구현된 컬럼 기반의 분산 데이터베이스로 실시간 조회 및 업데이트 할 수 있으며, 각각의 프로세스는 개인의 데이터를 비동기적으로 업데이트 할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;분산 데이터 처리 : MapReduce&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;대용량 데이터에 대한 분산 병렬 처리를 목적으로 만들어진 소프트웨어 프레임워크로 모든 데이터를 Key-Value로 구성&lt;/li&gt;
&lt;li&gt;맵, 셔플, 리듀스로 구성됨&lt;/li&gt;
&lt;li&gt;맵 : Key-Value 형태로 데이터를 취합&lt;/li&gt;
&lt;li&gt;셔플 : 데이터를 통합하여 처리&lt;/li&gt;
&lt;li&gt;리듀스 : 맵 처리된 데이터를 정리&lt;/li&gt;
&lt;li&gt;데이터를 디스크에 두고 처리하기 때문에 속도가 느림&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;리소스 관리 : 얀(YARN)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;하둡의 맵리듀스 처리 부분을 새롭게 만든 자원 관리 플랫폼으로, 리소스 매니저, 노드 매니저, 애플리케이션 마스터, 컨테이너로 구성됨&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 86px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style15&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 22px;&quot;&gt;
&lt;td style=&quot;width: 16.9768%; text-align: center; height: 22px;&quot;&gt;구 성&lt;/td&gt;
&lt;td style=&quot;width: 83.0232%; text-align: center; height: 22px;&quot;&gt;특 징&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 16px;&quot;&gt;
&lt;td style=&quot;width: 16.9768%; text-align: center; height: 16px;&quot;&gt;리소스 매니저&lt;/td&gt;
&lt;td style=&quot;width: 83.0232%; height: 16px;&quot;&gt;스케쥴러 역할을 수행하고 클러스터 이용률 최적화 수행&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 16px;&quot;&gt;
&lt;td style=&quot;width: 16.9768%; text-align: center; height: 16px;&quot;&gt;노드 매니저&lt;/td&gt;
&lt;td style=&quot;width: 83.0232%; height: 16px;&quot;&gt;각각의 노드 내 독립된 자원을 관리하고 리소스 매니저에게 전달 수행 및 컨테이너 관리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 16px;&quot;&gt;
&lt;td style=&quot;width: 16.9768%; text-align: center; height: 16px;&quot;&gt;애플리케이션 매니저&lt;/td&gt;
&lt;td style=&quot;width: 83.0232%; height: 16px;&quot;&gt;리소스 매니저와 자원의 교섭을 책임지고 컨테이너 실행&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 16px;&quot;&gt;
&lt;td style=&quot;width: 16.9768%; text-align: center; height: 16px;&quot;&gt;컨테이너&lt;/td&gt;
&lt;td style=&quot;width: 83.0232%; height: 16px;&quot;&gt;프로그램 구동을 위한 격리 환경을 지원하는 가상화 자원&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;인메모리 처리 : 아파치 스파크(Apache Spark)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;맵리듀스의 느린 속도를 개선하기 위한 하둡 기반 대용량 분산처리시스템으로, 스트리밍 데이터, 온라인 머신러닝 등 실시간으로 데이터 처리&lt;/li&gt;
&lt;li&gt;데이터를 인메모리에 두고 처리하므로 속도가 빠름&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데이터 가공 : Pig, Hive&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Pig : 대용량 데이터 집합을 분석하기 위한 플랫폼으로 맵리듀스를 사용하기 위한 스크립트 언어인 피크 라틴이라는 자체 언어 제공&lt;/li&gt;
&lt;li&gt;Hive : 하둡 기반 DW 솔루션으로 SQL과 매우 유사한 HiveQL이라는 쿼리 제공&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데이터 마이닝 : Mahout&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;하둡 기반으로 데이터 마이닝 알고리즘을 구현한 오픈소스로 다양한 알고리즘 지원&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;실시간 SQL 질의 : Impala, Tajo&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Impala : 하둡 기반의 실시간 SQL 질의 시스템으로 조회을 위한 인터페이스로 HiveQL을 지원하고, HBase와 연동 가능&lt;/li&gt;
&lt;li&gt;Tajo : 다양한 데이터 소스를 위한 하둡 기반의 ETL 기술을 이용하여 DW에 적재하는 시스템&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;워크플로우 관리 : Oozie&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;하둡 작업을 관리하는 워크플로우 및 코디네이터 시스템&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;분산 코디네이션 : Zookeeper&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;분산 환경에서 서버들 간의 상호 조정이 피룡한 다양한 서비스를 제공하는 기술로 분산 처리를 알맞게 처리하도록 조정하는 역할 수행&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;</description>
      <category>모각코</category>
      <author>PiLove</author>
      <guid isPermaLink="true">https://pi-love0314.tistory.com/30</guid>
      <comments>https://pi-love0314.tistory.com/entry/2%EA%B3%BC%EB%AA%A9-1%EC%9E%A5-%EC%A0%95%EB%A6%AC#entry30comment</comments>
      <pubDate>Fri, 2 Jan 2026 22:30:03 +0900</pubDate>
    </item>
    <item>
      <title>[영상처리] Week2-3. Point processing &amp;amp; Histogram equalization</title>
      <link>https://pi-love0314.tistory.com/entry/%EC%98%81%EC%83%81%EC%B2%98%EB%A6%AC-Point-processing-Histogram-equalization</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 이미지들은 너무 밝거나 어두워서 또는 주변 픽셀과의 대비가 낮아서 무슨 이미지인지 알아보기 힘든 경우가 있다. 이러한 이미지들은 특정한 처리를 통해 좀 더 선명하게 만들어줘야 한다. 오늘은 여러가지 처리기법 중 가장 기본적인 Point processing과 Histogram equalization에 대해 알아보려고 한다.&lt;/p&gt;
&lt;div style=&quot;border: 2px solid #009a87; border-radius: 5px; padding: 15px; box-shadow: 2px 2px 8px text-align: left;&quot;&gt;
&lt;p style=&quot;font-weight: bold; font-size: 20px; color: #009a87;&quot; data-ke-size=&quot;size23&quot;&gt; 목차&lt;/p&gt;
&lt;p style=&quot;margin: 5px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;color: #00796b; text-decoration: none;&quot; href=&quot;#no0&quot;&gt;➤ Point processing&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;margin: 5px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;color: #00796b; text-decoration: none;&quot; href=&quot;#no1&quot;&gt;➤ Histogram equalization&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;no0&quot; style=&quot;padding: 0.4em 1em 0.4em 0.5em; margin: 0.5em 0em; color: #000000; border-left: 10px solid #009a87; border-bottom: 2px #009a87 solid; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;Point processing&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Point processing이란 이미지의 각 픽셀을 독립적으로 처리하는 방식을 말한다. 주변 픽셀은 고려하지 않고 오로지 입력 픽셀 값만에 의존하여 출력 픽셀들을 계산한다. 아래 그림을 확인해보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;734&quot; data-origin-height=&quot;273&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dJrEOh/btsM5kLfVel/ZlD5rzYaKIkoaVsT0g5EU1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dJrEOh/btsM5kLfVel/ZlD5rzYaKIkoaVsT0g5EU1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dJrEOh/btsM5kLfVel/ZlD5rzYaKIkoaVsT0g5EU1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdJrEOh%2FbtsM5kLfVel%2FZlD5rzYaKIkoaVsT0g5EU1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;522&quot; height=&quot;194&quot; data-origin-width=&quot;734&quot; data-origin-height=&quot;273&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원본 이미지의 녹색 픽셀로부터 특정한 operation을 통해 출력 픽셀들의 값을 모두 결정했으므로 해당 과정은&amp;nbsp; Point processing에 해당한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약, 입력 이미지의 어떤 한 픽셀이 아닌 주변 픽셀 값들을 고려하여 출력 픽셀 값들을 결정한다면, 그건 필터링에 해당한다. 아래 그림 같은 경우는 필터링에 해당한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;732&quot; data-origin-height=&quot;268&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rWSl7/btsM4ZUS1ol/bY6pcvum7ckWLwTOQJ2xT1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rWSl7/btsM4ZUS1ol/bY6pcvum7ckWLwTOQJ2xT1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rWSl7/btsM4ZUS1ol/bY6pcvum7ckWLwTOQJ2xT1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrWSl7%2FbtsM4ZUS1ol%2FbY6pcvum7ckWLwTOQJ2xT1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;525&quot; height=&quot;192&quot; data-origin-width=&quot;732&quot; data-origin-height=&quot;268&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Point processing의 예제를 몇가지 확인해보자. 원본 이미지의 모든 픽셀 값들의 집합을 f(x)라고 하자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;756&quot; data-origin-height=&quot;404&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cAgpF8/btsM5zuBcdQ/J9kEhGHiYKFVt1PHyES1xk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cAgpF8/btsM5zuBcdQ/J9kEhGHiYKFVt1PHyES1xk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cAgpF8/btsM5zuBcdQ/J9kEhGHiYKFVt1PHyES1xk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcAgpF8%2FbtsM5zuBcdQ%2FJ9kEhGHiYKFVt1PHyES1xk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;709&quot; height=&quot;379&quot; data-origin-width=&quot;756&quot; data-origin-height=&quot;404&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입력 픽셀 값 f(x)에 대해 특정한 operation을 적용한다. f(x)에 대해 상수를 단순히 더하거나 빼서 밝기를 조절할 수 있고, f(x)에 대해 곱하거나 나누어서 대비를 조절할 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 수식으로 나타내면 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;378&quot; data-origin-height=&quot;25&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HAhIX/btsM6hfWH1R/ITGKgnXbudsdu71FAgxDf1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HAhIX/btsM6hfWH1R/ITGKgnXbudsdu71FAgxDf1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HAhIX/btsM6hfWH1R/ITGKgnXbudsdu71FAgxDf1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHAhIX%2FbtsM6hfWH1R%2FITGKgnXbudsdu71FAgxDf1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;378&quot; height=&quot;25&quot; data-origin-width=&quot;378&quot; data-origin-height=&quot;25&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;g(x, y) : 출력 이미지의 (x, y)위치의 픽셀 값&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;f(x, y) : 입력 이미지의 (x, y)위치의 픽셀 값&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;h : Intensity trnasformation function(변환 함수)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;를 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떤 이미지에 대해 위와 같은 수식을 적용하게 되면, 해당 이미지의 모든 위치의 픽셀에 대해 연산을 진행한다. 따라서 연산 수행 횟수를 줄이기 위해 같은 픽셀 값을 지니는 픽셀에 대해서는 연산을 하지 않는 것이 좋다. 따라서 수식으로 나타낼 때도 s = h(r) 로 나타내며 의미는 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;91&quot; data-origin-height=&quot;29&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rPfzG/btsM40sIPyp/QF5XL51aBnecnGFkQPwwU0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rPfzG/btsM40sIPyp/QF5XL51aBnecnGFkQPwwU0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rPfzG/btsM40sIPyp/QF5XL51aBnecnGFkQPwwU0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrPfzG%2FbtsM40sIPyp%2FQF5XL51aBnecnGFkQPwwU0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;91&quot; height=&quot;29&quot; data-origin-width=&quot;91&quot; data-origin-height=&quot;29&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;r : 입력 이미지의 픽셀 값들의 집합&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;s : 출력 이미지의 픽셀 값들의 집합&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래프로도 확인해보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;873&quot; data-origin-height=&quot;307&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lNQu5/btsM6Gzw7QB/7w59n7MWqgSAihKS4fKYSK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lNQu5/btsM6Gzw7QB/7w59n7MWqgSAihKS4fKYSK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lNQu5/btsM6Gzw7QB/7w59n7MWqgSAihKS4fKYSK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlNQu5%2FbtsM6Gzw7QB%2F7w59n7MWqgSAihKS4fKYSK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;873&quot; height=&quot;307&quot; data-origin-width=&quot;873&quot; data-origin-height=&quot;307&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;x축이 입력 이미지의 픽셀 값을 의미하며, y축이 Intensity transformation function을 적용한 출력 이미지의 픽셀 값을 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(a)의 경우, 어두운 픽셀 값들은 더 어둡게, 밝은 픽셀 값들은 더 밝게 만들어주고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(b)의 경우, Threshold 값 k를 지정하여, k보다 작은 픽셀 값에 대해서는 출력 픽셀을 0으로 만들고, k보다 큰 픽셀 값에 대해서는 1로 만들고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Point processing에서 자주 사용되는 Intensity transformation function인 &quot;Power-law(gamma) transformation&quot;에 대해서도 알아보자. 수식으로 나타내면 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;83&quot; data-origin-height=&quot;23&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WErLS/btsM6dq4HnW/uqJx80vFAsYukksYC3UFZk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WErLS/btsM6dq4HnW/uqJx80vFAsYukksYC3UFZk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WErLS/btsM6dq4HnW/uqJx80vFAsYukksYC3UFZk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWErLS%2FbtsM6dq4HnW%2FuqJx80vFAsYukksYC3UFZk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;83&quot; height=&quot;23&quot; data-origin-width=&quot;83&quot; data-origin-height=&quot;23&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;r : 입력 이미지의 픽셀 값들의 집합&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;s : 출력 이미지의 픽셀 값들의 집합&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;c : 상수 (보통 1로 설정)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; (gamma) : 밝기 조절을 결정하는 지수&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 수식에서 우리는  (gamma) 값을 조절하면서 이미지를 가공한다. 그래프를 통해  (gamma)의 변화에 따른 픽셀 값들의 변화를 확인해보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;824&quot; data-origin-height=&quot;477&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RS8IU/btsM4qkU3Yu/Q8HcwLfksfKlQ9JUNOenH0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RS8IU/btsM4qkU3Yu/Q8HcwLfksfKlQ9JUNOenH0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RS8IU/btsM4qkU3Yu/Q8HcwLfksfKlQ9JUNOenH0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRS8IU%2FbtsM4qkU3Yu%2FQ8HcwLfksfKlQ9JUNOenH0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;793&quot; height=&quot;459&quot; data-origin-width=&quot;824&quot; data-origin-height=&quot;477&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; (gamma) &amp;lt; 1 : 어두운 픽셀 값들은 밝아지고, 밝은 픽셀 값들은 더 밝아지고 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;rarr; 어두운 부분이 강조되고 전체적인 밝기가 밝아졌다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; (gamma) = 1 : 변화 x&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; (gamma) &amp;gt; 1 : 어두운 픽셀 값들은 더 어두워지고, 밝은 픽셀 값들은 어두워졌다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;rarr; 밝은 부분이 강조되고 전체적인 밝기가 어두워졌다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;371&quot; data-origin-height=&quot;488&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TLUpJ/btsM6gH7yqv/HvRQbXX2okBpJOyW6ypQT1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TLUpJ/btsM6gH7yqv/HvRQbXX2okBpJOyW6ypQT1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TLUpJ/btsM6gH7yqv/HvRQbXX2okBpJOyW6ypQT1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTLUpJ%2FbtsM6gH7yqv%2FHvRQbXX2okBpJOyW6ypQT1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;371&quot; height=&quot;488&quot; data-origin-width=&quot;371&quot; data-origin-height=&quot;488&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왼쪽 상단에 있는 이미지가 원본 이미지이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오른쪽 상단의 이미지  (gamma) = 0.6&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왼쪽 하단의 이미지  (gamma) = 0.4&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오른쪽 하단의 이미지  (gamma) = 0.3&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; (gamma)의 값이 작아질수록 이미지가 확실히 밝아지는 것을 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;483&quot; data-origin-height=&quot;490&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dkHzZj/btsM5WJVyir/ns8MaK5DwKkpNKuk9vC7G1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dkHzZj/btsM5WJVyir/ns8MaK5DwKkpNKuk9vC7G1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dkHzZj/btsM5WJVyir/ns8MaK5DwKkpNKuk9vC7G1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdkHzZj%2FbtsM5WJVyir%2Fns8MaK5DwKkpNKuk9vC7G1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;483&quot; height=&quot;490&quot; data-origin-width=&quot;483&quot; data-origin-height=&quot;490&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;왼쪽 상단에 있는 이미지가 원본 이미지이다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;오른쪽 상단의 이미지&lt;span&gt;&amp;nbsp;&lt;/span&gt; (gamma) = 3.0&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;왼쪽 하단의 이미지&lt;span&gt;&amp;nbsp;&lt;/span&gt; (gamma) = 4.0&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;오른쪽 하단의 이미지&lt;span&gt;&amp;nbsp;&lt;/span&gt; (gamma) = 5.0&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; (gamma)의 값이 커질수록 이미지가 확실히 어두워지는 것을 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;no1&quot; style=&quot;padding: 0.4em 1em 0.4em 0.5em; margin: 0.5em 0em; color: #000000; border-left: 10px solid #009a87; border-bottom: 2px #009a87 solid; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Histogram equalization&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Histogram은 특정 이미지에 대해 0~255 사이의 픽셀 값들의 분포를 나타낸다. 아래 예시를 확인해보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;572&quot; data-origin-height=&quot;278&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/csQ2fG/btsM6DbLq4k/8IWzjTtAZmI5Hflf0uxe7k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/csQ2fG/btsM6DbLq4k/8IWzjTtAZmI5Hflf0uxe7k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/csQ2fG/btsM6DbLq4k/8IWzjTtAZmI5Hflf0uxe7k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcsQ2fG%2FbtsM6DbLq4k%2F8IWzjTtAZmI5Hflf0uxe7k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;572&quot; height=&quot;278&quot; data-origin-width=&quot;572&quot; data-origin-height=&quot;278&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;534&quot; data-origin-height=&quot;222&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bPnn0Q/btsM4JxY0xu/8RvrkAdh9ZKK7f2TQRTUQ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bPnn0Q/btsM4JxY0xu/8RvrkAdh9ZKK7f2TQRTUQ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bPnn0Q/btsM4JxY0xu/8RvrkAdh9ZKK7f2TQRTUQ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbPnn0Q%2FbtsM4JxY0xu%2F8RvrkAdh9ZKK7f2TQRTUQ0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;534&quot; height=&quot;222&quot; data-origin-width=&quot;534&quot; data-origin-height=&quot;222&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 그림처럼 특정 구역에 픽셀이 집중적으로 모여있을 때는, Histogram stretching을 사용하여 픽셀 값의 영역을 재배치하여 대비(contrast)를 높일 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;0 ~ 255 사이의 픽셀 값을 0~15의 level로 구분하여 나타내고, 각 level별로 픽셀 값이 몇개씩 분포해있는지 나타낸 예제가 있다. 아래 그림을 보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;629&quot; data-origin-height=&quot;52&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bLMXLY/btsM32KGIKO/ahipgS9GQqni7o7AdFkEw0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bLMXLY/btsM32KGIKO/ahipgS9GQqni7o7AdFkEw0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bLMXLY/btsM32KGIKO/ahipgS9GQqni7o7AdFkEw0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbLMXLY%2FbtsM32KGIKO%2FahipgS9GQqni7o7AdFkEw0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;629&quot; height=&quot;52&quot; data-origin-width=&quot;629&quot; data-origin-height=&quot;52&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock floatLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;277&quot; data-origin-height=&quot;228&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/k5AWn/btsM4JLzkS5/0tQF5aztW5kWbodbrzh1fk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/k5AWn/btsM4JLzkS5/0tQF5aztW5kWbodbrzh1fk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/k5AWn/btsM4JLzkS5/0tQF5aztW5kWbodbrzh1fk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fk5AWn%2FbtsM4JLzkS5%2F0tQF5aztW5kWbodbrzh1fk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;277&quot; height=&quot;228&quot; data-origin-width=&quot;277&quot; data-origin-height=&quot;228&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미지의 픽셀값이 대체적으로 5 ~ 9 사이에 몰려있는 것을 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이에 대해서 stretching function을 적용해보자. 수식으로 나타내면 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;290&quot; data-origin-height=&quot;68&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Sptys/btsM6ATCmxY/kiJUQznPstMCDQOo7B4JdK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Sptys/btsM6ATCmxY/kiJUQznPstMCDQOo7B4JdK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Sptys/btsM6ATCmxY/kiJUQznPstMCDQOo7B4JdK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSptys%2FbtsM6ATCmxY%2FkiJUQznPstMCDQOo7B4JdK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;290&quot; height=&quot;68&quot; data-origin-width=&quot;290&quot; data-origin-height=&quot;68&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock floatLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;94&quot; data-origin-height=&quot;21&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/buy8pX/btsM6clruPb/rKZR4fihYeklkz740BNjN1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/buy8pX/btsM6clruPb/rKZR4fihYeklkz740BNjN1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/buy8pX/btsM6clruPb/rKZR4fihYeklkz740BNjN1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbuy8pX%2FbtsM6clruPb%2FrKZR4fihYeklkz740BNjN1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;94&quot; height=&quot;21&quot; data-origin-width=&quot;94&quot; data-origin-height=&quot;21&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;a i+1 : 이미지 내 픽셀 값이 몰려있는 영역의 최대 grey 레벨&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;a i : 이미지 내 픽셀 값이 몰려있는 영역의 최소 grey 레벨&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;101&quot; data-origin-height=&quot;28&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bEdwdc/btsM5vFY61M/5iLTkkQBOUO1mHIeZuQht1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bEdwdc/btsM5vFY61M/5iLTkkQBOUO1mHIeZuQht1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bEdwdc/btsM5vFY61M/5iLTkkQBOUO1mHIeZuQht1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbEdwdc%2FbtsM5vFY61M%2F5iLTkkQBOUO1mHIeZuQht1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;101&quot; height=&quot;28&quot; data-origin-width=&quot;101&quot; data-origin-height=&quot;28&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;b i + 1 : 퍼뜨리고자 하는 영역의 최대 grey 레벨&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;b i : 퍼뜨리고자 하는 영역의 최소 grey 레벨&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래프로 확인해보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;627&quot; data-origin-height=&quot;387&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pHYLb/btsM5BTvKsf/QENRiCKhsAFCIGOYS7nx50/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pHYLb/btsM5BTvKsf/QENRiCKhsAFCIGOYS7nx50/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pHYLb/btsM5BTvKsf/QENRiCKhsAFCIGOYS7nx50/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpHYLb%2FbtsM5BTvKsf%2FQENRiCKhsAFCIGOYS7nx50%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;627&quot; height=&quot;387&quot; data-origin-width=&quot;627&quot; data-origin-height=&quot;387&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;610&quot; data-origin-height=&quot;387&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzxWrW/btsM6EIvSpi/cY2SkCwHyFwfmU4RCPg1S1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzxWrW/btsM6EIvSpi/cY2SkCwHyFwfmU4RCPg1S1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzxWrW/btsM6EIvSpi/cY2SkCwHyFwfmU4RCPg1S1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbzxWrW%2FbtsM6EIvSpi%2FcY2SkCwHyFwfmU4RCPg1S1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;610&quot; height=&quot;387&quot; data-origin-width=&quot;610&quot; data-origin-height=&quot;387&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;확실히 5~9 사이에 분포하던 픽셀 값이 넓게 펼쳐진 것을 확인할 수 있다. 그러나 넓게 펼쳐지기만 하고 픽셀 값이 균등하게 분포되어 있지 않다. 이를 위한 기법이 Histogram equalization이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Histogram equalization의 가장 이상적인 케이스는 다음과 같이 모든 픽셀 값들을 grey level에 대해 균등하게 분포시키는 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;406&quot; data-origin-height=&quot;110&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cH336n/btsM5qredNh/pwVK3l6GPptAgZ78iJFMiK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cH336n/btsM5qredNh/pwVK3l6GPptAgZ78iJFMiK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cH336n/btsM5qredNh/pwVK3l6GPptAgZ78iJFMiK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcH336n%2FbtsM5qredNh%2FpwVK3l6GPptAgZ78iJFMiK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;406&quot; height=&quot;110&quot; data-origin-width=&quot;406&quot; data-origin-height=&quot;110&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 그래프를 확률 밀도 함수(PDF, Probability Density Function)으로도 나타낼 수 있다. 원래 픽셀 값은 0~255의 정수로 나타내기 때문에 PDF로 나타낼 수 없지만, 그럼에도 불구하고 이론적인 모델링을 위해 &quot;연속적인 경우&quot;를 가정하고 PDF로 표현한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 그래프를 PDF로 나타낸 그림은 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;648&quot; data-origin-height=&quot;172&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dOX4mN/btsM6CKJJXz/9VUKGtRvTP0WLQoNpev8o0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dOX4mN/btsM6CKJJXz/9VUKGtRvTP0WLQoNpev8o0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dOX4mN/btsM6CKJJXz/9VUKGtRvTP0WLQoNpev8o0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdOX4mN%2FbtsM6CKJJXz%2F9VUKGtRvTP0WLQoNpev8o0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;558&quot; height=&quot;148&quot; data-origin-width=&quot;648&quot; data-origin-height=&quot;172&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 입력 이미지와 출력 이미지의 픽셀 수 자체는 같기 때문에 다음 수식이 성립한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;148&quot; data-origin-height=&quot;48&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c3eS5K/btsM41d6rwY/AwNVSRCZkfQu8tMKPYpDMK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c3eS5K/btsM41d6rwY/AwNVSRCZkfQu8tMKPYpDMK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c3eS5K/btsM41d6rwY/AwNVSRCZkfQu8tMKPYpDMK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc3eS5K%2FbtsM41d6rwY%2FAwNVSRCZkfQu8tMKPYpDMK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;148&quot; height=&quot;48&quot; data-origin-width=&quot;148&quot; data-origin-height=&quot;48&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입력 이미지에 대한 PDF : $f_R(r)$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;출력 이미지에 대한 PDF : $f_S(s)$&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;$f_R(r)$을 $f_S(s)$로 변환하려면, 다음과 같은 함수를 적용해야 한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;88&quot; data-origin-height=&quot;95&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/coz86N/btsM6VJ5SCZ/HaL8pDNWnmEPUzsBRZIC6K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/coz86N/btsM6VJ5SCZ/HaL8pDNWnmEPUzsBRZIC6K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/coz86N/btsM6VJ5SCZ/HaL8pDNWnmEPUzsBRZIC6K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcoz86N%2FbtsM6VJ5SCZ%2FHaL8pDNWnmEPUzsBRZIC6K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;88&quot; height=&quot;95&quot; data-origin-width=&quot;88&quot; data-origin-height=&quot;95&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 각각의 픽셀 값들을 T(r)의 값으로 변환해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 T(r)은 monotonic increasing function이다.&lt;br /&gt;Monotonic increasing function은 값은 같아도 되지만 감소하지 않는 함수를 말한다.&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 수식들을 토대로 $f_R(r)$ 은 다음과 같이 전개될 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;216&quot; data-origin-height=&quot;36&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CYYiO/btsM656MtEi/av1N2oVWannJd9qFBr6xm1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CYYiO/btsM656MtEi/av1N2oVWannJd9qFBr6xm1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CYYiO/btsM656MtEi/av1N2oVWannJd9qFBr6xm1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCYYiO%2FbtsM656MtEi%2Fav1N2oVWannJd9qFBr6xm1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;216&quot; height=&quot;36&quot; data-origin-width=&quot;216&quot; data-origin-height=&quot;36&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 알 수 있는 건 T(r)의 도함수가 $f_R(r)$과 같아진다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 곧 T(r)이 monotonic increasing function이라는 것을 증명한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 수식에서 $f_R(r) = T'(r)$ 이 성립하므로, 아래 수식도 성립한다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;186&quot; data-origin-height=&quot;37&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cdAbjf/btsM4K4Ka3T/aiqOKD4K6tMzHGE3dklut0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cdAbjf/btsM4K4Ka3T/aiqOKD4K6tMzHGE3dklut0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cdAbjf/btsM4K4Ka3T/aiqOKD4K6tMzHGE3dklut0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcdAbjf%2FbtsM4K4Ka3T%2FaiqOKD4K6tMzHGE3dklut0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;186&quot; height=&quot;37&quot; data-origin-width=&quot;186&quot; data-origin-height=&quot;37&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 수식은 $T(r)$ 을 누적 분포 함수(CDF)로 정의한 수식이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;210&quot; data-origin-height=&quot;46&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/6RbjI/btsM5QQrE46/eGxDTjZzqkmpxZdEC6mxLk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/6RbjI/btsM5QQrE46/eGxDTjZzqkmpxZdEC6mxLk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/6RbjI/btsM5QQrE46/eGxDTjZzqkmpxZdEC6mxLk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F6RbjI%2FbtsM5QQrE46%2FeGxDTjZzqkmpxZdEC6mxLk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;210&quot; height=&quot;46&quot; data-origin-width=&quot;210&quot; data-origin-height=&quot;46&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 위 수식은 continuous case를 가정한 이론적인 모델이다. 실제 이미지는 discrete하므로, 다음과 같은 근사가 필요하다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;215&quot; data-origin-height=&quot;46&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c3X4mT/btsM5DKDmRE/Hfg4u3Iv7Il72j78DzJoWk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c3X4mT/btsM5DKDmRE/Hfg4u3Iv7Il72j78DzJoWk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c3X4mT/btsM5DKDmRE/Hfg4u3Iv7Il72j78DzJoWk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc3X4mT%2FbtsM5DKDmRE%2FHfg4u3Iv7Il72j78DzJoWk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;215&quot; height=&quot;46&quot; data-origin-width=&quot;215&quot; data-origin-height=&quot;46&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 수식을 적용한 예제를 표로 나타내서 확인해보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;452&quot; data-origin-height=&quot;185&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQq0Cz/btsM5St2OE3/OVDSvhsAnb8KeymxgSmKY1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQq0Cz/btsM5St2OE3/OVDSvhsAnb8KeymxgSmKY1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQq0Cz/btsM5St2OE3/OVDSvhsAnb8KeymxgSmKY1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQq0Cz%2FbtsM5St2OE3%2FOVDSvhsAnb8KeymxgSmKY1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;452&quot; height=&quot;185&quot; data-origin-width=&quot;452&quot; data-origin-height=&quot;185&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>CS/영상처리</category>
      <author>PiLove</author>
      <guid isPermaLink="true">https://pi-love0314.tistory.com/23</guid>
      <comments>https://pi-love0314.tistory.com/entry/%EC%98%81%EC%83%81%EC%B2%98%EB%A6%AC-Point-processing-Histogram-equalization#entry23comment</comments>
      <pubDate>Thu, 3 Apr 2025 00:18:16 +0900</pubDate>
    </item>
    <item>
      <title>[데이터베이스] Week3. Relational Database</title>
      <link>https://pi-love0314.tistory.com/entry/%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4-Relational-Database</link>
      <description>&lt;h2 id=&quot;no0&quot; style=&quot;padding: 0.4em 1em 0.4em 0.5em; margin: 0.5em 0em; color: #000000; border-left: 10px solid #009a87; border-bottom: 2px #009a87 solid; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Relational database&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Relational database(관계형 데이터베이스)는 데이터들 사이에 정의된 관계가 있는 데이터베이스를 의미한다. Relational database에 대해 이해하기 위해 relation에 대해 먼저 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;!-- 특징 박스 --&gt;&lt;/p&gt;
&lt;div style=&quot;border: 2px solid #009a87; border-radius: 5px; padding: 15px; text-align: left;&quot;&gt;&lt;!-- 제목 --&gt;
&lt;p style=&quot;font-weight: bold; font-size: 18px; color: #009a87; margin: 0 0 5px 0; display: flex;&quot; data-ke-size=&quot;size16&quot;&gt;  Relation(Table)&lt;/p&gt;
&lt;!-- 리스트 대신 p 태그로 정리 --&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; 개체를 표현하기 위한 데이터 구조&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; 2차원 테이블로 표현&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶행(row, tuple): 개체를 표현. 관련된 데이터 값들의 모임.&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶열(column, attribute): 각 행의 값들의 의미를 해석하는 데 사용.&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; Relation은 tuple들의 집합&lt;/b&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단한 예제를 하나 확인해보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;334&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xu6gu/btsM4k4mxE8/rVV7HiAlbIrmhIY2PjArj1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xu6gu/btsM4k4mxE8/rVV7HiAlbIrmhIY2PjArj1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xu6gu/btsM4k4mxE8/rVV7HiAlbIrmhIY2PjArj1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fxu6gu%2FbtsM4k4mxE8%2FrVV7HiAlbIrmhIY2PjArj1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;653&quot; height=&quot;282&quot; data-origin-width=&quot;773&quot; data-origin-height=&quot;334&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Movie라는 relation(table)은 2차원 테이블 형태로 구성되어 있으며, 각 행은 객체로써 tuple이라고 부른다. 이 tuple들의 집합이 해당 relation에 대한 relation status(relation extension)이다. 각 열은 해당 열에 대한 값들의 의미를 뜻하며 attribute라고 부른다. 이 attribute들의 집합이 해당 relation에 대한 relation schema(relation intension)이다. 위 relation에서 relation schema는 &quot;Movie(movieId, title, genre, length, rating)&quot;으로 표기한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;no1&quot; style=&quot;padding: 0.4em 1em 0.4em 0.5em; margin: 0.5em 0em; color: #000000; border-left: 10px solid #009a87; border-bottom: 2px #009a87 solid; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Relational database 스키마 기반 제약 조건&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Schema는 stored database의 structure + constraints로 이루어져있다. 이전 목차에서 relational database의 structure에 대해 알아보았다면, 이번 목차에서는 constraint에 대해 알아볼 예정이다. Constraint는 relational database의 특정 attribute에 값이나 타입 등의 제한을 두거나 relation 사이에 지켜져야 하는 규칙 등을 의미한다. 하나하나 알아보도록 한자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;!-- 특징 박스 --&gt;&lt;/p&gt;
&lt;div style=&quot;border: 2px solid #009a87; border-radius: 5px; padding: 15px; text-align: left;&quot;&gt;&lt;!-- 제목 --&gt;
&lt;p style=&quot;font-weight: bold; font-size: 18px; color: #009a87; margin: 0 0 5px 0; display: flex;&quot; data-ke-size=&quot;size16&quot;&gt;  Relational database의 스키마 기반 제약 조건들&lt;/p&gt;
&lt;!-- 리스트 대신 p 태그로 정리 --&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt; 도메인 제약 조건(Domain constraints)&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt; 널 제약 조건(Null constraints)&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt; 키 제약 조건(Key constraints)&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt; 엔티티 무결성 제약 조건(Entity Integrity Constraints)&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt; 참조 무결성 제약 조건(Referential Integrity Constraints)&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;no2&quot; style=&quot;padding: 0.4em 1em 0.4em 0.5em; margin: 0.5em 0em; color: #000000; border-left: 10px solid #009a87; border-bottom: 2px #009a87 solid; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Domain constraints&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Domain constraints는 각각의 tuple내에서 각각의 attribute A에 대하여 A의 값이 A의 도메인에 속하는 원자값이어야 함을 의미한다. 말이 어렵지만 예시를 들어 생각해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Relation Avitivity에 'weather'이라는 attribute가 있다고 가정하자. 'weather' 는 'sunny, rainy, ...' 등의 날씨와 관련된 문자열만을 도메인으로 갖는다. 이러한 경우, 그 어떤 tuple이든 'weather'이라는 attribute에 대해서는 위에서 언급한 'sunny, rainy ...' 등의 날씨와 관련한 문자열 집합의 원소를 가져야 한다는 뜻이다. 'weather'이라는 attribute에 대해 뜬금없이 'football'이라는 값을 가지는 건 허용하지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 SQL로 domain constraints을 명시한 예제이다.&lt;/p&gt;
&lt;pre id=&quot;code_1743475081291&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;create table Movie( 
	movieId varchar(10) primary key,
	title varchar(100) unique,
	genre varchar(32),
	rating varchar(5), 
    	check (rating in(&amp;lsquo;G&amp;rsquo;, &amp;lsquo;PG&amp;rsquo;, &amp;lsquo;PG-13&amp;rsquo;, &amp;lsquo;R&amp;rsquo;, &amp;lsquo;NC-17&amp;rsquo;)
    &amp;hellip;
)

create table Rental( 
	accountId int,
	videoId varchar(10),
	dateRented datetime,
	dateDue datetime,
	&amp;hellip;
	check (dateRented &amp;lt;= dateDue)
 )&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Relation Movie의 'rating'은 시청 등급이라는 뜻이며, 이에 대한 명확한 표준 등급이 있으므로 해당 집합을 명시해주었다. Relation Rental의 'dateRented'는 대출 날짜를 의미하며 'dateDue'는 반납 날짜를 의미한다. 반납 날짜는 대출 날짜 뒤의 날이므로 이에 대한 domain constraints를 명시해주었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;no3&quot; style=&quot;padding: 0.4em 1em 0.4em 0.5em; margin: 0.5em 0em; color: #000000; border-left: 10px solid #009a87; border-bottom: 2px #009a87 solid; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Null constraints&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Attribute는 그 의미에 따라 Null값이 필요할 수도, 필요하지 않을 수도 있다. 아래 코드를 예제로 생각해보자.&lt;/p&gt;
&lt;pre id=&quot;code_1743475513008&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;create table VideoTape (
	videoId varchar(10) primary key,
	movieId varchar(10) not null default &amp;lsquo;000-00-000&amp;rsquo;
	references Movie,
	storeId int references Store 
)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Relation VideoTape의 'movieId'는 절대로 Null 값이 될 수 없다. VideoTape의 'movieId'가 relation Movie의 'movieId'를 참조하고 있기 때문이다. 또한 상식적으로 현실세계에서 비디오테이프에 저장된 영화에 대해 고유 식별 번호를 정의하지 않는 것도 말이 안된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;no4&quot; style=&quot;padding: 0.4em 1em 0.4em 0.5em; margin: 0.5em 0em; color: #000000; border-left: 10px solid #009a87; border-bottom: 2px #009a87 solid; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Key constraints&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Key constraints는 relation에서 특정 attribute에 대해 각 tuple을 고유하게 식별해야 함을 의미한다. 즉, key로 지정된 attribute에는 중복된 값도 존재할 수 없다. Super key는 1개 이상의 attribute를 집합으로 했을 때 유일성을 만족하는 attribute 집합이다. 예를 들어 생각해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Relation R에 대해 'SSN'이라는 key가 있고, 'name', 'age'라는 attribute가 있다고 가정하자. 'SSN'은 그 자체로 각 tuple을 구별할 수 있는 유일성을 지니고 있다. 따라서 'SSN'은 key인 동시에 super key이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;{'SSN', 'name'} 또한 각 tuple을 구별할 수 있는 유일성을 지니고 있다. 따라서 super key에 해당한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;{'SSN', 'age'}와 {'SSN', 'age', 'name'} 또한 super key에 해당한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만일 relation schema가 하나 이상의 key를 가질 경우, 각 키를 'candidate key'라고 한다. 그리고 candidate key 중 하나를 'primary key'로 지정한다. Primary key를 지정하면, 이 primary key로 각 tuple들을 식별한다. Primary key이외의 다른 candidate key는 'unique key'라고 부른다. 이를 정리하면 아래와 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;!-- 특징 박스 --&gt;&lt;/p&gt;
&lt;div style=&quot;border: 2px solid #009a87; border-radius: 5px; padding: 15px; text-align: left;&quot;&gt;&lt;!-- 제목 --&gt;
&lt;p style=&quot;font-weight: bold; font-size: 18px; color: #009a87; margin: 0 0 5px 0; display: flex;&quot; data-ke-size=&quot;size16&quot;&gt;  Key&lt;/p&gt;
&lt;!-- 리스트 대신 p 태그로 정리 --&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt; Key&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶각 tuple을 고유하게 식별할 수 있는 attribute&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt; Super key&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶각 tuple을 고유하게 식별할 수 있는 attribute 집합&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt; Candidate key&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶해당 relation schema가 하나 이상의 key를 가질 때, 각 key = candidate key&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt; Primary key&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶Candidate key 중 개발자가 지정한 하나의 key로, 해당 key로 각 tuple을 식별하게 됨&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt; Unique key&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶Primary key를 제외한 다른 Candidate key&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;no5&quot; style=&quot;padding: 0.4em 1em 0.4em 0.5em; margin: 0.5em 0em; color: #000000; border-left: 10px solid #009a87; border-bottom: 2px #009a87 solid; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Entity Integrity Constraints&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EIC(Entity Integrity Constraints)는 어떠한 primary key 값도 Null 값이 될 수 없음을 의미한다. Primary key로 각 tuple을 식별하므로 primary key 값이 Null이 되면 튜플을 식별할 수 없기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;no6&quot; style=&quot;padding: 0.4em 1em 0.4em 0.5em; margin: 0.5em 0em; color: #000000; border-left: 10px solid #009a87; border-bottom: 2px #009a87 solid; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Reference Integrity Constraints&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;RIC(Reference Integrity Constraints)를 이해하기 위해선 foreign key에 대해 먼저 알아야 한다. Foreign key의 조건은 아래와 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;!-- 특징 박스 --&gt;&lt;/p&gt;
&lt;div style=&quot;border: 2px solid #009a87; border-radius: 5px; padding: 15px; text-align: left;&quot;&gt;&lt;!-- 제목 --&gt;
&lt;p style=&quot;font-weight: bold; font-size: 18px; color: #009a87; margin: 0 0 5px 0; display: flex;&quot; data-ke-size=&quot;size16&quot;&gt;  Foreign key&lt;/p&gt;
&lt;!-- 리스트 대신 p 태그로 정리 --&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;Rleation schema R1의 어떤 attribute 집합 FK가 아래 규칙을 만족하면, FK는 relation R2를 참조하는 R1의 foreign key이다.( R1 : 참조한 relation, R2 : 참조된 relation )&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt; FK의 attribute는 R2의 primary key, PK의 attribute와 동일한 domain을 가진다.&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt; 현재 상태 R1의 한 tuple t1의 FK값은 현재 상태 R2의 어떤 tuple t2내의 PK값과 일치하거나 Null값을 가진다.&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 예제이다.&lt;/p&gt;
&lt;pre id=&quot;code_1743480033631&quot; class=&quot;sql&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;sql&quot;&gt;&lt;code&gt;create table VideoTape (
	videoId varchar(10) primary key,
	movieId varchar(10) not null default &amp;lsquo;000-00-000&amp;rsquo;
	references Movie,
	storeId int references Store 
)

create table Store (
	storeId int(10) primary key,
    	street varchar(20) not null,
    	city varchar(20) not null,
    	manager varchar(12) not null,
)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드를 보면, VideoTape의 'storeId'가 Store의 primary key인 'storeId'를 참조하는 것을 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 Schema 다이어그램으로 표시하면 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;685&quot; data-origin-height=&quot;256&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ba7AC8/btsM2IZQo2Y/0alzyZwkTCVwKStlXb8KP1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ba7AC8/btsM2IZQo2Y/0alzyZwkTCVwKStlXb8KP1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ba7AC8/btsM2IZQo2Y/0alzyZwkTCVwKStlXb8KP1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fba7AC8%2FbtsM2IZQo2Y%2F0alzyZwkTCVwKStlXb8KP1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;482&quot; height=&quot;180&quot; data-origin-width=&quot;685&quot; data-origin-height=&quot;256&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;밑줄이 쳐진 attribute는 primary key를 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 RIC가 위반된 경우에는 참조하는 혹은 참조되는 relation의 각 attribute의 값을 확인해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>CS/데이터베이스</category>
      <author>PiLove</author>
      <guid isPermaLink="true">https://pi-love0314.tistory.com/22</guid>
      <comments>https://pi-love0314.tistory.com/entry/%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4-Relational-Database#entry22comment</comments>
      <pubDate>Tue, 1 Apr 2025 13:07:29 +0900</pubDate>
    </item>
    <item>
      <title>[데이터베이스] Week2. 정보관리와 데이터베이스 시스템</title>
      <link>https://pi-love0314.tistory.com/entry/%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4-%EC%A0%95%EB%B3%B4%EA%B4%80%EB%A6%AC%EC%99%80-%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4-%EC%8B%9C%EC%8A%A4%ED%85%9C</link>
      <description>&lt;p style=&quot;margin: 5px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;no0&quot; style=&quot;padding: 0.4em 1em 0.4em 0.5em; margin: 0.5em 0em; color: #000000; border-left: 10px solid #009a87; border-bottom: 2px #009a87 solid; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;정보 시스템&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정보 시스템을 이해하기 위해선 데이터와 정보의 정확한 정의에 대해 먼저 알아야 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;!-- 특징 박스 --&gt;&lt;/p&gt;
&lt;div style=&quot;border: 2px solid #009a87; border-radius: 5px; padding: 15px; text-align: left;&quot;&gt;&lt;!-- 제목 --&gt;
&lt;p style=&quot;font-weight: bold; font-size: 18px; color: #009a87; margin: 0 0 5px 0; display: flex;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  데이터와 정보&lt;/span&gt;&lt;/p&gt;
&lt;!-- 리스트 대신 p 태그로 정리 --&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt; 데이터&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶비트들의 모음&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶현실세계로부터 단순한 관찰이나 측정을 통해 수집된 사실이나 값&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt; 정보&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶데이터를 처리한 결과&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶의사결정의 근거&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정보 시스템(Information System)이란, 한 기관을 위해 데이터를 수집, 조직, 저장하고 필요 시에 처리하여 의사 결정에 유용한 정보를 생성, 분배하는 수단이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1018&quot; data-origin-height=&quot;399&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zfvFk/btsM1mJAsWT/1kdkG4WmNPmnNPsHKeYcNK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zfvFk/btsM1mJAsWT/1kdkG4WmNPmnNPsHKeYcNK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zfvFk/btsM1mJAsWT/1kdkG4WmNPmnNPsHKeYcNK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzfvFk%2FbtsM1mJAsWT%2F1kdkG4WmNPmnNPsHKeYcNK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;411&quot; height=&quot;161&quot; data-origin-width=&quot;1018&quot; data-origin-height=&quot;399&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞으로 배우고자 하는 &quot;데이터베이스 시스템&quot;은 정보 시스템의 코어가 되는 시스템이다. 데이터베이스 시스템은 정보 처리 시스템이 그 기능을 효과적으로 수행할 수 있게 하는 기본이 되는 도구이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;no1&quot; style=&quot;padding: 0.4em 1em 0.4em 0.5em; margin: 0.5em 0em; color: #000000; border-left: 10px solid #009a87; border-bottom: 2px #009a87 solid; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;데이터베이스 시스템 구성 요소&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터베이스 시스템을 단순화해서 나타내면 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;646&quot; data-origin-height=&quot;777&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bsSKuB/btsM2otEyeu/wUP1N9rnBkkTZceVVNPLq0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bsSKuB/btsM2otEyeu/wUP1N9rnBkkTZceVVNPLq0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bsSKuB/btsM2otEyeu/wUP1N9rnBkkTZceVVNPLq0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbsSKuB%2FbtsM2otEyeu%2FwUP1N9rnBkkTZceVVNPLq0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;406&quot; height=&quot;488&quot; data-origin-width=&quot;646&quot; data-origin-height=&quot;777&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;!-- 특징 박스 --&gt;&lt;/p&gt;
&lt;div style=&quot;border: 2px solid #009a87; border-radius: 5px; padding: 15px; text-align: left;&quot;&gt;&lt;!-- 제목 --&gt;
&lt;p style=&quot;font-weight: bold; font-size: 18px; color: #009a87; margin: 0 0 5px 0; display: flex;&quot; data-ke-size=&quot;size16&quot;&gt;  데이터베이스 시스템의 구성 요소&lt;/p&gt;
&lt;!-- 리스트 대신 p 태그로 정리 --&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; 물리적 데이터베이스(Stored Database)&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶실제 데이터 내용을 포함하는 파일들의 집합&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; 스키마(Schema, Meta-Data)&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶물리적 데이터베이스의 내용을 명세하는 데이터&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; 데이터베이스 관리 시스템&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;(DBMS, DataBase Management System)&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶데이터베이스 안의 내용을 접근하고 변경할 수 있는 &lt;br /&gt;&amp;nbsp; &amp;nbsp; 소프트웨어&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶Oracle, MS SQL Server, IBM DB2, ...&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; 데이터 정의, 관리 언어(DDL, DCL)&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶스키마를 정의하고 데이터베이스에 접근하기 위해&lt;br /&gt;&amp;nbsp; &amp;nbsp; 사용하는 언어&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Users/Programmers 가 DB에서 어떤 데이터를 질의(Query)하고자 명령어를 작성하면, 해당 DBMS에서 해당 명령어를 처리하고 Stored database에 접근하여 해당 데이터를 반환한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 실제로 &lt;b&gt;값들이 저장되는 데이터베이스(Stored database)에 대해 알아보자&lt;/b&gt;. 데이터베이스의 정의는 &quot;한 조직의 여러 응용 시스템들이 공용(Shared)하기 위해 통합(Integrated), 저장(Stored)한 운영(Operational)데이터의 집합&quot;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;!-- 특징 박스 --&gt;&lt;/p&gt;
&lt;div style=&quot;border: 2px solid #009a87; border-radius: 5px; padding: 15px; text-align: left;&quot;&gt;&lt;!-- 제목 --&gt;
&lt;p style=&quot;font-weight: bold; font-size: 18px; color: #009a87; margin: 0 0 5px 0; display: flex;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  데이터베이스 정의&lt;/span&gt;&lt;/p&gt;
&lt;!-- 리스트 대신 p 태그로 정리 --&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; 통합된 데이터(Integrated data)&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶최소의 중복 또는 통제된 중복&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; 저장 데이터(Stored data)&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶컴퓨터가 접근 가능한 저장 매체에 저장&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; 운영 데이터(Operational data)&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶한 조직의 고유 기능을 수행하기 위해 필요한 데이터&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; 공용 데이터(Shared data)&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶한 조직에 있는 여러 응용 프로그램이 공동으로 소유, 유지, 이용하는 데이터&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터베이스의 특징도 알아보자. 데이터베이스는 질의의 속도도 빨라야 하고, 현실세계의 값이 바뀌면 데이터베이스의 값도 바뀌어야 한다. 여러 사람이 질의를 할 수도 있어야 하며, 질의하고자 하는 데이터의 값에 따라 그 값을 반환해야 한다. 정리하면 아래와 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;!-- 특징 박스 --&gt;&lt;/p&gt;
&lt;div style=&quot;border: 2px solid #009a87; border-radius: 5px; padding: 15px; text-align: left;&quot;&gt;&lt;!-- 제목 --&gt;
&lt;p style=&quot;font-weight: bold; font-size: 18px; color: #009a87; margin: 0 0 5px 0; display: flex;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  데이터베이스 특징&lt;/span&gt;&lt;/p&gt;
&lt;!-- 리스트 대신 p 태그로 정리 --&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; 온라인 접근성(Online accessibilities)&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶질의에 대한 실시간 처리 및 응답&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; 계속적인 변화(Continuous Evolution)&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶새로운 데이터의 삽입, 기존 데이터의 삭제, 갱신으로 현실세계의 변화하는 값을 반영&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; 동시 공용(Concurrent Sharing)&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶서로 다른 목적을 가진 응용들을 여러 사용자가 동시에 사용&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; 값에 따른 참조(Content Reference)&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶위치나 메모리 주소가 아닌 값에 따른 참&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에는 스키마(Schema, meta-data)에 대해 알아보자. 스키마는 위에서 설명한 데이터베이스(Stored database)에 대한 설명을 기술한 데이터이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;!-- 특징 박스 --&gt;&lt;/p&gt;
&lt;div style=&quot;border: 2px solid #009a87; border-radius: 5px; padding: 15px; text-align: left;&quot;&gt;&lt;!-- 제목 --&gt;
&lt;p style=&quot;font-weight: bold; font-size: 18px; color: #009a87; margin: 0 0 5px 0; display: flex;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  스키마(Schema, Meta-data)&lt;/span&gt;&lt;/p&gt;
&lt;!-- 리스트 대신 p 태그로 정리 --&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt; 데이터베이스에 대한 설명을 기술&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶데이터베이스 구조, 타입, 제약 조건&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt; DBMS 카탈로그(Catalog)에 저장&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DBMS는 이 스키마가 저장된 카탈로그로부터 DB에 대한 정의를 가져와 DB에 접근한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 DBMS에 대해 알아보자. 위에서 설명했듯이 DBMS는 데이터베이스 안의 내용을 접근하고 변경할 수 있는 소프트웨어이다. 데이터베이스를 관리하기 위한 DBMS의 여러 기능에 대해 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;!-- 특징 박스 --&gt;&lt;/p&gt;
&lt;div style=&quot;border: 2px solid #009a87; border-radius: 5px; padding: 15px; text-align: left;&quot;&gt;&lt;!-- 제목 --&gt;
&lt;p style=&quot;font-weight: bold; font-size: 18px; color: #009a87; margin: 0 0 5px 0; display: flex;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  DBMS의 기능&lt;/span&gt;&lt;/p&gt;
&lt;!-- 리스트 대신 p 태그로 정리 --&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt; 정의(Definition)&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶데이터의 논리적 구조를 명세&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶물리적 저장 구조 명세&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶물리적 / 논리적 사상 명세&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt; 조작(Manipulation)&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶Read : 검색(SELECT)기능 지원&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶Write : 삽입(INSERT), 삭제(DELETE), &lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;갱신(UPDATE)&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt; 기능 지원&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt; 제어(Control)&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶데이터의 삽입, 삭제, 갱신 기능에 대한 데이터의 무결성(Integrity) 유지&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶사용자의 데이터 접근 권한 관리&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>CS/데이터베이스</category>
      <author>PiLove</author>
      <guid isPermaLink="true">https://pi-love0314.tistory.com/21</guid>
      <comments>https://pi-love0314.tistory.com/entry/%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4-%EC%A0%95%EB%B3%B4%EA%B4%80%EB%A6%AC%EC%99%80-%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4-%EC%8B%9C%EC%8A%A4%ED%85%9C#entry21comment</comments>
      <pubDate>Tue, 1 Apr 2025 10:13:23 +0900</pubDate>
    </item>
    <item>
      <title>[프로그래밍언어개론] Syntax and Parsing</title>
      <link>https://pi-love0314.tistory.com/entry/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D%EC%96%B8%EC%96%B4%EA%B0%9C%EB%A1%A0-Syntax-and-Parsing</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;[프로그래밍언어개론]의 목적은 프로그래밍 언어를 구성하는 구문(Syntax)과 의미(Sematics)를 이해하여 다양한 프로그래밍 언어를 빠르고 정확하게 습득할 수 있는 능력을 섭렵하는 것이다. 오늘은 프로그래밍 언어가 입력 문자열을 어떻게 인식하는 지에 대한 이야기이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로그래밍 언어는 알파벳 문자열로 구성된 문자열 집합이다. 그러나 알파벳 문자열 중에는 &quot;프로그래밍 언어&quot;가 아닌 문자열도 분명히 존재한다. 즉, 프로그래밍 언어는 알파벳 문자열로 구성된 문자열 집합 중에 &quot;특정 문법&quot;에 부합하는 문자열을 의미한다. &quot;입력으로 들어오는 문자열이 &quot;특정 문법&quot;에 부합하는 알파벳 문자열 집합인가?&quot;를 판별하는 역할은 구문분석기(Syntax analyzer 또는 Parser)가 하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘은 입력 문자열이 특정 language에 포함되는가를 어떻게 확인하는지와 그 language를 정의하는 여러가지 expression에 대해 알아볼 예정이다.&lt;/p&gt;
&lt;div style=&quot;border: 2px solid #009a87; border-radius: 5px; padding: 15px; box-shadow: 2px 2px 8px text-align: left;&quot;&gt;
&lt;p style=&quot;font-weight: bold; font-size: 20px; color: #009a87;&quot; data-ke-size=&quot;size23&quot;&gt; Syntax and Parsing&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p style=&quot;margin: 5px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;color: #00796b; text-decoration: none;&quot; href=&quot;#no0&quot;&gt;➤ Chomsky hierarchy&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;margin: 5px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;color: #00796b; text-decoration: none;&quot; href=&quot;#no1&quot;&gt;➤ Regular language &amp;amp; Regularexpression&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;margin: 5px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;color: #00796b; text-decoration: none;&quot; href=&quot;#no2&quot;&gt;➤ Finite (state) automata&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;margin: 5px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;color: #00796b; text-decoration: none;&quot; href=&quot;#no3&quot;&gt;➤ Overall structure of compilers and interpreters&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;margin: 5px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;color: #00796b; text-decoration: none;&quot; href=&quot;#no4&quot;&gt;➤ Overall sㅐ&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;margin: 5px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;color: #00796b; text-decoration: none;&quot; href=&quot;#no5&quot;&gt;➤ Overall of compilers and &lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;margin: 5px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;color: #00796b; text-decoration: none;&quot; href=&quot;#no6&quot;&gt;➤ Overall of compiters&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;no0&quot; style=&quot;padding: 0.4em 1em 0.4em 0.5em; margin: 0.5em 0em; color: #000000; border-left: 10px solid #009a87; border-bottom: 2px #009a87 solid; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Chomsky hierarchy&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;691&quot; data-origin-height=&quot;508&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UWMx7/btsM02cOoAD/J5HVm4sH6iYaAtdlkRZfV1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UWMx7/btsM02cOoAD/J5HVm4sH6iYaAtdlkRZfV1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UWMx7/btsM02cOoAD/J5HVm4sH6iYaAtdlkRZfV1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUWMx7%2FbtsM02cOoAD%2FJ5HVm4sH6iYaAtdlkRZfV1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;691&quot; height=&quot;508&quot; data-origin-width=&quot;691&quot; data-origin-height=&quot;508&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Chomsky hierarchy는 언어의 표현력에 따라 계층으로 나타낸 것이다. 타원이 작을수록 해당 언어의 표현력이 작음을 나타낸다. 타원마다 automata가 존재하는데, 각각의 오토마타는 &quot;이 문자열이 이 language에 포함되는가?&quot;를 확인하는 역할을 한다. 오늘은 Regular language와 Context-Free language에 대해 간단하게 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고로 대부분의 프로그래밍 언어는 Context-Sensitive Language이거나 Context-Free Language에 속한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;no1&quot; style=&quot;padding: 0.4em 1em 0.4em 0.5em; margin: 0.5em 0em; color: #000000; border-left: 10px solid #009a87; border-bottom: 2px #009a87 solid; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Regular language &amp;amp; Regular expression&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Regular language는 기계가 인식할 수 있는 가장 간단한 형태의 language이다. 그리고 Regualr expression은 이러한 regular language를 정의하기 위한 문법을 의미한다. 주로 입력으로 주어진 문자열을 Tokenizing할 때 사용되며, token list로 만들어진 문자열은 automata에게 넘겨져서 language에 속하는 지 판별된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;777&quot; data-origin-height=&quot;242&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bNq8GO/btsM0so5ywu/laXTVkzuO0fBHkcUBAPKo0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bNq8GO/btsM0so5ywu/laXTVkzuO0fBHkcUBAPKo0/img.png&quot; data-alt=&quot;'&amp;amp;Sigma;'는 소문자 알파벳으로 이루어진 문자의 집합이며, ' &amp;amp;Sigma;+'는 소문자 알파벳으로 이루어진 문자열 무한집합을 의미한다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bNq8GO/btsM0so5ywu/laXTVkzuO0fBHkcUBAPKo0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbNq8GO%2FbtsM0so5ywu%2FlaXTVkzuO0fBHkcUBAPKo0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;713&quot; height=&quot;222&quot; data-origin-width=&quot;777&quot; data-origin-height=&quot;242&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;'&amp;Sigma;'는 소문자 알파벳으로 이루어진 문자의 집합이며, ' &amp;Sigma;+'는 소문자 알파벳으로 이루어진 문자열 무한집합을 의미한다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 그림에서 &quot;::=&quot;는 R이 오른쪽의 값으로 치환될 수 있음을 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 regular expression을 간결하게 사용하기 위한 연산자이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;930&quot; data-origin-height=&quot;349&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/chjThE/btsMZ4BWboS/9khIQN2dxBolMLiWLha4Ck/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/chjThE/btsMZ4BWboS/9khIQN2dxBolMLiWLha4Ck/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/chjThE/btsMZ4BWboS/9khIQN2dxBolMLiWLha4Ck/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FchjThE%2FbtsMZ4BWboS%2F9khIQN2dxBolMLiWLha4Ck%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;703&quot; height=&quot;264&quot; data-origin-width=&quot;930&quot; data-origin-height=&quot;349&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Regular expression의 연산자들 사이에는 다음과 같은 우선순위가 존재한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;!-- 특징 박스 --&gt;&lt;/p&gt;
&lt;div style=&quot;border: 2px solid #009a87; border-radius: 5px; padding: 15px; text-align: left;&quot;&gt;&lt;!-- 제목 --&gt;
&lt;p style=&quot;font-weight: bold; font-size: 18px; color: #009a87; margin: 0 0 5px 0; display: flex;&quot; data-ke-size=&quot;size16&quot;&gt; &amp;nbsp; &lt;b&gt;Kleene closure &amp;gt; Concatenation &amp;gt; Union&lt;/b&gt;&lt;/p&gt;
&lt;!-- 리스트 대신 p 태그로 정리 --&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;  |   = ( ) |   = { ,  }&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;    &amp;lowast; =  (  &amp;lowast; ) = { ,  ,  ,  , &amp;hellip;}&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;    |   &amp;lowast; =   | (  &amp;lowast; ) = { ,  ,  ,  ,  , &amp;hellip;}&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Regular expression을 활용하여 간단한 email address language를 정의해보자. 보통 대부분의 email은 다음과 같은 형태를 갖는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[문자열]@[문자열].[문자열]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 regular expression으로 나타내면 아래와 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;692&quot; data-origin-height=&quot;44&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HY4NN/btsM2YT3iGd/Fr5oG0kkeghowhJ1BCiqnk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HY4NN/btsM2YT3iGd/Fr5oG0kkeghowhJ1BCiqnk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HY4NN/btsM2YT3iGd/Fr5oG0kkeghowhJ1BCiqnk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHY4NN%2FbtsM2YT3iGd%2FFr5oG0kkeghowhJ1BCiqnk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;535&quot; height=&quot;34&quot; data-origin-width=&quot;692&quot; data-origin-height=&quot;44&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 해당 문법은 약한 표현력을 가진다. &quot;pi@cnu.ac.kr&quot; 이라는 문자열을 L(email)의 언어로 인식하지 않는다. 이를 보완하려면, 뒤에 &quot;.[문자열]&quot;이 더 나올 수 있음을 표현해야 한다. 아래 표현식을 보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;944&quot; data-origin-height=&quot;34&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cX6vXE/btsM14UZ5Wn/pevE3a655i0HbLlR1Si1Hk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cX6vXE/btsM14UZ5Wn/pevE3a655i0HbLlR1Si1Hk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cX6vXE/btsM14UZ5Wn/pevE3a655i0HbLlR1Si1Hk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcX6vXE%2FbtsM14UZ5Wn%2FpevE3a655i0HbLlR1Si1Hk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;777&quot; height=&quot;28&quot; data-origin-width=&quot;944&quot; data-origin-height=&quot;34&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아직도 문제가 있다. &quot;pi@cnu.ac.kr&quot; 이라는 문자열은 이제 L(email)의 언어로 인식하지만, &quot;@&quot; 뒤에 &quot;.&quot;이 4개 이상 올 때는 인식할 수가 없다. 예를 들어 &quot;pi@o.cnu.ac.kr&quot; 은 인식할 수 없다. 이를 보완하려면 &quot;@&quot; 뒤 &quot;.[문자열]&quot;의 개수에 제한을 두면 안된다. 아래와 같이 마지막 expression인 (.[a-z][a-z]*)에 kleene closure를 사용하면 &quot;.[문자열]&quot;의 제한을 없앨 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;887&quot; data-origin-height=&quot;46&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cKWbnH/btsM0oNHN31/UUWjlAF3fqfmZGn2aTOkVK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cKWbnH/btsM0oNHN31/UUWjlAF3fqfmZGn2aTOkVK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cKWbnH/btsM0oNHN31/UUWjlAF3fqfmZGn2aTOkVK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcKWbnH%2FbtsM0oNHN31%2FUUWjlAF3fqfmZGn2aTOkVK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;726&quot; height=&quot;38&quot; data-origin-width=&quot;887&quot; data-origin-height=&quot;46&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;no2&quot; style=&quot;padding: 0.4em 1em 0.4em 0.5em; margin: 0.5em 0em; color: #000000; border-left: 10px solid #009a87; border-bottom: 2px #009a87 solid; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Finite (state) automata&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;regular expression이 regular language를 정의하기 위한 &quot;문법&quot;이였다면, Finite state automata는 주어진 문자열 s가 regular language에 속하는 지 판별하는 &quot;추상 기계&quot;이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Finite state automata는 입력으로 들어온 문자열에 대해서 &quot;상태(state)&quot;를 변경하게 되는데, 이 상태에 따라서 regular language에 속하는 지를 판별한다. Finite state automat를 기호로 표현하면 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;446&quot; data-origin-height=&quot;347&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c1JgW1/btsM0pslcv3/8Ckr5WYNqKrDdYkj7eRGh1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c1JgW1/btsM0pslcv3/8Ckr5WYNqKrDdYkj7eRGh1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c1JgW1/btsM0pslcv3/8Ckr5WYNqKrDdYkj7eRGh1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc1JgW1%2FbtsM0pslcv3%2F8Ckr5WYNqKrDdYkj7eRGh1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;294&quot; height=&quot;229&quot; data-origin-width=&quot;446&quot; data-origin-height=&quot;347&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;Q&quot;는 해당 automata가 가질 수 있는 모든 상태를 나타낸다. 그리고 &quot;전이함수&quot;는 입력 알파벳에 대하여 기계의 상태를 어떻게 변화할 지를 정의한 함수이다. 이전 목차에서 예시로 들었던 L(email) language에 대해 automata를 정의하면 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1038&quot; data-origin-height=&quot;493&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bC315R/btsM0H06m7X/0GT0Wu6wZkiBT6PLQR5ZN1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bC315R/btsM0H06m7X/0GT0Wu6wZkiBT6PLQR5ZN1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bC315R/btsM0H06m7X/0GT0Wu6wZkiBT6PLQR5ZN1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbC315R%2FbtsM0H06m7X%2F0GT0Wu6wZkiBT6PLQR5ZN1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1038&quot; height=&quot;493&quot; data-origin-width=&quot;1038&quot; data-origin-height=&quot;493&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;!-- 특징 박스 --&gt;&lt;/p&gt;
&lt;div style=&quot;border: 2px solid #009a87; border-radius: 5px; padding: 15px; text-align: left;&quot;&gt;&lt;!-- 제목 --&gt;
&lt;p style=&quot;font-weight: bold; font-size: 18px; color: #009a87; margin: 0 0 5px 0; display: flex;&quot; data-ke-size=&quot;size16&quot;&gt;  &quot;[문자열1]@[문자열2].[문자열3](.[문자열4]))&quot;에 대한 동작&lt;/p&gt;
&lt;!-- 리스트 대신 p 태그로 정리 --&gt;&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;입력 문자열을 모두 순회했을 때 기계의 상태가 q5이거나 q7이면 정상적으로 종료한다.&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;  ------------------------------------------&lt;br /&gt;처음 기계의 상태는 q0로 시작한다. 이때 &quot;입력 문자열의 첫 번째 문자 = 소문자 알파벳&quot;이면 q1으로 상태를 변경한다. 그리고 q1 상태에서 &quot;다음 문자 = 소문자 알파벳&quot;이면 &quot;@&quot;가 나올 때까지 q1 상태 그대로 유지한다. q1 상태에서 &quot;@&quot;가 나오면 q2 상태로 변경한다.&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶&amp;nbsp; &quot;[문자열1]@&quot; 까지에 대한 상태 변화이다.&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;  ------------------------------------------&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;q2 상태에서 &quot;다음 문자열의 첫 번째 문자 = 소문자 알파벳&quot;이면 q3 상태로 변경한다. q3 상태에서 &quot;다음 문자 = 소문자 알파벳&quot;이면 q3 상태를 유지한다. q3 상태에서 &quot;.&quot;가 나오면 q4 상태로 변경한다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶ &quot;@[문자열2].&quot; 까지에 대한 상태 변화이다.&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;  ------------------------------------------&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;q4 상태에서 &quot;다음 문자열의 첫 번째 문자 = 소문자 알파벳&quot;이면 q5 상태로 변경한다. q5 상태에서 &quot;다음 문자 = 소문자 알파벳&quot;이면 q5 상태를 유지한다. q5 상태에서 &quot;.&quot;가 나오면 q6 상태로 변경한다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶ &quot;.[문자열3](.&quot; 까지에 대한 상태 변화이다.&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;  ------------------------------------------&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;q6 상태에서 &quot;다음 문자열의 첫 번째 문자 = 소문자 알파벳&quot; 이면 q7 상태로 변경한다. q7 상태에서 &quot;다음 문자 = 소문자 알파벳&quot;이면 q7 상태를 유지한다.&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶ &quot;(.[문자열4])&quot; 까지에 대한 상태 변화이다.&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;L(email)을 아래와 같은 모형으로 나타낼 수도 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1099&quot; data-origin-height=&quot;134&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cPJLHm/btsM1iT1xBO/jXkUYhtacUQcxOwYnIsKiK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cPJLHm/btsM1iT1xBO/jXkUYhtacUQcxOwYnIsKiK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cPJLHm/btsM1iT1xBO/jXkUYhtacUQcxOwYnIsKiK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcPJLHm%2FbtsM1iT1xBO%2FjXkUYhtacUQcxOwYnIsKiK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1099&quot; height=&quot;134&quot; data-origin-width=&quot;1099&quot; data-origin-height=&quot;134&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;no3&quot; style=&quot;padding: 0.4em 1em 0.4em 0.5em; margin: 0.5em 0em; color: #000000; border-left: 10px solid #009a87; border-bottom: 2px #009a87 solid; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Overall structure of compilers and interpreters&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1145&quot; data-origin-height=&quot;347&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Dw56s/btsM14m9OMi/aGK1tQHtnkpi6g2r0vyQr1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Dw56s/btsM14m9OMi/aGK1tQHtnkpi6g2r0vyQr1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Dw56s/btsM14m9OMi/aGK1tQHtnkpi6g2r0vyQr1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDw56s%2FbtsM14m9OMi%2FaGK1tQHtnkpi6g2r0vyQr1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1145&quot; height=&quot;347&quot; data-origin-width=&quot;1145&quot; data-origin-height=&quot;347&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 지금까지 알아본 Regular expression은 Regualr language에 대한 문법이다. 이는 automata에 의해 활용되어 입력으로 들어온 문자열을 잘게 잘라서 token list 형태로 만들어준다. 이 과정을 Tokenizing 혹은 Lexing 이라고 한다. 여기서 token이란, 프로그래밍 언어에서의 어휘 항목에 대한 표현을 의미한다. 예를 들어 &quot;let x = 3 in f x&quot;라는 문자열에 대해 &quot;let&quot;이라는 키워드도 하나의 어휘 항목이고 &quot;in&quot;이라는 키워드도 하나의 어휘 항목이다. &quot;x&quot;라는 변수도 어휘 항목이고 &quot;=&quot;, &quot;3&quot;, &quot;f&quot;, &quot;x&quot; 모두 어휘 항목이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 입력으로 들어온 문자열에 대해서 해당 언어의 어휘 항목 즉, token list 형태로 만들어주는 것을 Tokenizing 혹은 Lexing이라고 하며 이 과정은 그림의 &quot;Lexical Analysis&quot;에서 이루어진다. 이 과정에서 문제가 발생하면 어휘 분석 오류(lexing error)를 보고한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후 token list는 &quot;Syntax Analysis&quot;를 거쳐 &quot;AST(Abstract Syntax Tree)&quot;로 변환된다. 이 과정에서는 CFG(Context-Free Grammer, Context-Free laguage를 정의하는 문법)를 사용한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Regular expression으로 어휘 항목을 분석했다면, &lt;span style=&quot;color: #ee2323;&quot;&gt;Context-Free Grammer로 어휘 항목들의 구조적인 묶음, 즉 프로그래밍 언어의 구문(문장 구조, syntax)을 정의&lt;/span&gt;하는 것이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 Chomsky hierarchy에 따르면 Context-Free Language는 Regular Language보다 좋은 표현력을 가지고 있다. 그렇다면 어휘 항목을 정의하는 것도 CFG를 활용하면 되는 것 아니냐는 의문이 들 수 있다. 물론 가능은 하다. 하지만 과한 접근이며 처리 비용도 더 크기 때문에 사용하지 않는다. CFG는 Regular expression보다 표현력이 큰 만큼 비용이 크다. 어휘 항목을 정의하는 것은 간단한 일이기 때문에 굳이 CFG를 사용하여 프로그램의 무게를 늘릴 필요가 없다는 의미이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;no4&quot; style=&quot;padding: 0.4em 1em 0.4em 0.5em; margin: 0.5em 0em; color: #000000; border-left: 10px solid #009a87; border-bottom: 2px #009a87 solid; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;CFG(Context-Free Grammer)&lt;b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전 항목에서 알아보았듯이 CFG는 Syntax Analysis에서 token list를 받아 프로그래밍 언어의 구문을 정의하는 역할을 한다. CFG는 아래 3가지로 구성되어 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;!-- 특징 박스 --&gt;&lt;/p&gt;
&lt;div style=&quot;border: 2px solid #009a87; border-radius: 5px; padding: 15px; text-align: left;&quot;&gt;&lt;!-- 제목 --&gt;
&lt;p style=&quot;font-weight: bold; font-size: 18px; color: #009a87; margin: 0 0 5px 0; display: flex;&quot; data-ke-size=&quot;size16&quot;&gt;  CFG 구성요소&lt;/p&gt;
&lt;!-- 리스트 대신 p 태그로 정리 --&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt; Terminal&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶기초 기호(literal)로써 치환되지 않는 기호&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt; Non-terminal&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶Production에 의해 치환되는 기호&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt; Production&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶Non-terminal을 치환하는 규칙&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단한 예시를 하나 들어보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;684&quot; data-origin-height=&quot;274&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dwkzH0/btsM2atVMrO/tD5DuWZBF29b679iHWHQ11/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dwkzH0/btsM2atVMrO/tD5DuWZBF29b679iHWHQ11/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dwkzH0/btsM2atVMrO/tD5DuWZBF29b679iHWHQ11/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdwkzH0%2FbtsM2atVMrO%2FtD5DuWZBF29b679iHWHQ11%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;477&quot; height=&quot;191&quot; data-origin-width=&quot;684&quot; data-origin-height=&quot;274&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A = 빈 문자열&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A = (A) = ()&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A = (A) = ((A)) = (())&lt;br /&gt;A는 위와 같이 계~속 치환될 수 있다.&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CFG의 엄밀한 정의는 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;!-- 특징 박스 --&gt;&lt;/p&gt;
&lt;div style=&quot;border: 2px solid #009a87; border-radius: 5px; padding: 15px; text-align: left;&quot;&gt;&lt;!-- 제목 --&gt;
&lt;p style=&quot;font-weight: bold; font-size: 18px; color: #009a87; margin: 0 0 5px 0; display: flex;&quot; data-ke-size=&quot;size16&quot;&gt;  G = (&amp;Sigma;, N, P, S)&lt;/p&gt;
&lt;!-- 리스트 대신 p 태그로 정리 --&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;b&gt;G는 S로부터 생성할 수 있는 모든 문자열을 나타내는 문법이다.&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;  &amp;Sigma;: terminal의 유한집합&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;  N: nonterminal의 유한집합&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;  P: production의 유한집합&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt; &lt;span&gt; S: 시작 nonterminal (S &amp;isin; N)&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;G를 아래와 같이 정의했다고 하자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1002&quot; data-origin-height=&quot;468&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Ou5qL/btsM2zfWhdG/7QgcSpaJS1pWSKKg19kqiK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ou5qL/btsM2zfWhdG/7QgcSpaJS1pWSKKg19kqiK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Ou5qL/btsM2zfWhdG/7QgcSpaJS1pWSKKg19kqiK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOu5qL%2FbtsM2zfWhdG%2F7QgcSpaJS1pWSKKg19kqiK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;620&quot; height=&quot;290&quot; data-origin-width=&quot;1002&quot; data-origin-height=&quot;468&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;G의 원소는 시작 non-terminal인 E로부터 나타낼 수 있는 모든 문자열 집합이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;G = {n, n+n, n-n, n+n+n, n+n-n, ...}&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 이렇게 CFG를 정의하니 너무나 길고 복잡하게 느껴진다. 이 때문에 CFG 기술을 위한 표기법이 따로 있는데 이를 BNF(Backus-Naur Form)이라고 부른다. 위 그림에서 정의했던 CFG를 아래와 같이 표기할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;749&quot; data-origin-height=&quot;156&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dtI0qq/btsM2ZFsh3M/zTPOFbPHw22egJ1YjkTMy0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dtI0qq/btsM2ZFsh3M/zTPOFbPHw22egJ1YjkTMy0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dtI0qq/btsM2ZFsh3M/zTPOFbPHw22egJ1YjkTMy0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdtI0qq%2FbtsM2ZFsh3M%2FzTPOFbPHw22egJ1YjkTMy0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;615&quot; height=&quot;128&quot; data-origin-width=&quot;749&quot; data-origin-height=&quot;156&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;n을 0~9 사이의 숫자로 변경하여 다시 비교해보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1081&quot; data-origin-height=&quot;345&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Ltw05/btsM19ofnoz/3QPyuA7yrNRot32NJWqVE0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ltw05/btsM19ofnoz/3QPyuA7yrNRot32NJWqVE0/img.png&quot; data-alt=&quot;Backus-Naur Form에서 CFG의 non-terminal이 2개 이상일 때, 가장 위에 있는 non-terminal이 시작 non-terminal이다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Ltw05/btsM19ofnoz/3QPyuA7yrNRot32NJWqVE0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLtw05%2FbtsM19ofnoz%2F3QPyuA7yrNRot32NJWqVE0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1081&quot; height=&quot;345&quot; data-origin-width=&quot;1081&quot; data-origin-height=&quot;345&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Backus-Naur Form에서 CFG의 non-terminal이 2개 이상일 때, 가장 위에 있는 non-terminal이 시작 non-terminal이다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BNF를 사용한 것이 사용하지 않았을 때보다 훨~씬 간결한 것을 볼 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;no5&quot; style=&quot;padding: 0.4em 1em 0.4em 0.5em; margin: 0.5em 0em; color: #000000; border-left: 10px solid #009a87; border-bottom: 2px #009a87 solid; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;Derivation &amp;amp; Parse&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;!-- 특징 박스 --&gt;&lt;/p&gt;
&lt;div style=&quot;border: 2px solid #009a87; border-radius: 5px; padding: 15px; text-align: left;&quot;&gt;&lt;!-- 제목 --&gt;
&lt;p style=&quot;font-weight: bold; font-size: 18px; color: #009a87; margin: 0 0 5px 0; display: flex;&quot; data-ke-size=&quot;size16&quot;&gt;  Derivation &amp;amp; Parse&lt;/p&gt;
&lt;!-- 리스트 대신 p 태그로 정리 --&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt; Derivation&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶정의한 CFG를 활용하여 시작 non-terminal로 부터 문자열을 생성하는 과정 (Parse의 반대 과정)&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶위에서 제시한 CFG에 대한 Derivation 예시&lt;/p&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;724&quot; data-origin-height=&quot;53&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GDK6I/btsM2ynOTZi/FsDaYsORegqNXkNOnDLKeK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GDK6I/btsM2ynOTZi/FsDaYsORegqNXkNOnDLKeK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GDK6I/btsM2ynOTZi/FsDaYsORegqNXkNOnDLKeK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGDK6I%2FbtsM2ynOTZi%2FFsDaYsORegqNXkNOnDLKeK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;382&quot; height=&quot;28&quot; data-origin-width=&quot;724&quot; data-origin-height=&quot;53&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt; Parse&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶정의한 CFG를 활용하여 입력 문자열이 문법에 부합하는 지 확인하는 과정 (Derivation의 반대 과정)&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶위에서 제시한 CFG에 대한 Parse 예시&lt;/p&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;718&quot; data-origin-height=&quot;52&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKtR4h/btsM1a9ou3R/TbSh98KxtF5TkGrWmSbDJ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKtR4h/btsM1a9ou3R/TbSh98KxtF5TkGrWmSbDJ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKtR4h/btsM1a9ou3R/TbSh98KxtF5TkGrWmSbDJ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKtR4h%2FbtsM1a9ou3R%2FTbSh98KxtF5TkGrWmSbDJ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;373&quot; height=&quot;27&quot; data-origin-width=&quot;718&quot; data-origin-height=&quot;52&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Derivation이나 Parse는 보통 tree형태로 표현하게 된다. 다음과 같은 tree를 Parse tree(or derivation tree)라고 한다. 위에서 아래로 읽으면 Derivation tree이고, 아래에서 위로 읽으면 Parse tree이므로 둘을 구분해서 나타내지는 않는다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;264&quot; data-origin-height=&quot;337&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pfC0k/btsM1mVZ2fW/vZR8kHEp3kryJ4Lz5g4nuk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pfC0k/btsM1mVZ2fW/vZR8kHEp3kryJ4Lz5g4nuk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pfC0k/btsM1mVZ2fW/vZR8kHEp3kryJ4Lz5g4nuk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpfC0k%2FbtsM1mVZ2fW%2FvZR8kHEp3kryJ4Lz5g4nuk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;153&quot; height=&quot;195&quot; data-origin-width=&quot;264&quot; data-origin-height=&quot;337&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입력 문자열에 대한 Parsing을 진행할 때, 여러 방식으로 파싱될 수 있는 문법이 존재한다. 이러한 경우를 ambiguos(모호)하다라고 표현하는데, 하나의 문자열에 대한 여러개의 서로 다른 parse tree가 존재하므로 적절한 parsing 방법이 필요하다. 아래는 ambiguous grammer 예시이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1165&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b9vZGX/btsM2JpoWwG/CKdhbML9x4VVOv1O9qdir0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b9vZGX/btsM2JpoWwG/CKdhbML9x4VVOv1O9qdir0/img.png&quot; data-alt=&quot;&amp;quot;1 + 3 - 2&amp;quot; 가 2개의 서로 다른 parse tree로 표현된다&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b9vZGX/btsM2JpoWwG/CKdhbML9x4VVOv1O9qdir0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb9vZGX%2FbtsM2JpoWwG%2FCKdhbML9x4VVOv1O9qdir0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;240&quot; data-origin-width=&quot;1165&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;&quot;1 + 3 - 2&quot; 가 2개의 서로 다른 parse tree로 표현된다&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 경우, 두 가지 방향의 derivation 중 하나를 선택해야 한다. Left-most derivation(좌측 우선 유도)와 Right-most derivation(우측 우선 유도) 중 하나로 일관되게 표현해야 한다. Left-most derivation과 Right-most derivation은 이름 그대로 가장 왼쪽 혹은 가장 오른쪽에 있는 non-terminal부터 유도를 한다는 뜻이다. 아래는 예시이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1217&quot; data-origin-height=&quot;431&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b0qPjk/btsM2IxewfQ/LgTngKUn5ZWgdLCnPOCn70/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b0qPjk/btsM2IxewfQ/LgTngKUn5ZWgdLCnPOCn70/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b0qPjk/btsM2IxewfQ/LgTngKUn5ZWgdLCnPOCn70/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb0qPjk%2FbtsM2IxewfQ%2FLgTngKUn5ZWgdLCnPOCn70%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;694&quot; height=&quot;246&quot; data-origin-width=&quot;1217&quot; data-origin-height=&quot;431&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;derivation의 방향을 결정했다면, parsing은 다음 2가지 중 하나를 결정하게 된다. Left-most derivation을 사용할 경우 LL parsing(top-down)을 진행하게 된다. top-down 형식은 parse의 방향이 derivation과 동일하다. 위에서부터 아래로, non-terminal로부터 입력 문자열을 만들어낼 수 있는지를 확인한다. Right-most derivation을 사용할 경우 LR parsing(bottom-up)을 진행하게 된다. bottom-up형식은 아래서부터 위로, 입력 문자열로부터 non-terminal을 만들어가는 것을 의미한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;886&quot; data-origin-height=&quot;385&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cVDBKc/btsM19hyuNY/vcObBgiPrKJCsug6qLnAq0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cVDBKc/btsM19hyuNY/vcObBgiPrKJCsug6qLnAq0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cVDBKc/btsM19hyuNY/vcObBgiPrKJCsug6qLnAq0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcVDBKc%2FbtsM19hyuNY%2FvcObBgiPrKJCsug6qLnAq0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;610&quot; height=&quot;265&quot; data-origin-width=&quot;886&quot; data-origin-height=&quot;385&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 이렇게 parsing될 수 있는 문법들을 LL grammer / language, LR grammer / language라고 부르고, 이들은 모두 Context-free grammer의 부분집합이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;!-- 특징 박스 --&gt;&lt;/p&gt;
&lt;div style=&quot;border: 2px solid #009a87; border-radius: 5px; padding: 15px; text-align: left;&quot;&gt;&lt;!-- 제목 --&gt;
&lt;p style=&quot;font-weight: bold; font-size: 18px; color: #009a87; margin: 0 0 5px 0; display: flex;&quot; data-ke-size=&quot;size16&quot;&gt; &amp;nbsp; LL and LR&amp;nbsp;&lt;/p&gt;
&lt;!-- 리스트 대신 p 태그로 정리 --&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt; LL grammer / language&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶ LL 파싱으로 인식될 수 있는 모호하지 않은 문법 / 언어&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt; LR grammer / language&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶ LR 파싱으로 인식될 수 있는 모호하지 않은 문법 / 언어&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LL(k) 또는 LR(k)도 존재하는데, 이때 k는 ambiguity(모호성)를 제거하기 위해 미리보는 토큰의 개수(lookahead)를 의미한다. 여기서 lookahead란, parsing할 때 &lt;span style=&quot;color: #ee2323;&quot;&gt;&quot;현재까지의 token을 어떤 non-terminal로 치환할 지 결정하기 위해, 미리 확인하는 토큰의 개수&quot;&lt;/span&gt;를 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시로 LR(k) parsing을 진행한다고 하자. 그리고 입력 문자열이 &quot;1 + 3 * 2&quot; 라고 하자. 이때 lookahead가 0일 때 발생할 수 있는 문제를 생각해보자. 우선 lexing을 진행하면 token list가 만들어지고 해당 list에는 ['1'; '+'; '3'; '*'; '2']과 같은 형식으로 원소들이 존재할 것이다. 그리고 parsing을 진행하기 위해 stack을 만드는데, 이 stack은 push된 token에 대하여 termianl로 만들 수 있으면 무조건 만든다고 가정하자. 아래는 예시로 사용할 CFG이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;469&quot; data-origin-height=&quot;84&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ck0nsy/btsM05guuue/W8GgjZZidnRGTLWiFBUHQ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ck0nsy/btsM05guuue/W8GgjZZidnRGTLWiFBUHQ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ck0nsy/btsM05guuue/W8GgjZZidnRGTLWiFBUHQ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fck0nsy%2FbtsM05guuue%2FW8GgjZZidnRGTLWiFBUHQ0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;357&quot; height=&quot;64&quot; data-origin-width=&quot;469&quot; data-origin-height=&quot;84&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;lookahead가 0인 경우를 생각해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;!-- 특징 박스 --&gt;&lt;/p&gt;
&lt;div style=&quot;border: 2px solid #009a87; border-radius: 5px; padding: 15px; text-align: left;&quot;&gt;&lt;!-- 제목 --&gt;
&lt;p style=&quot;font-weight: bold; font-size: 18px; color: #009a87; margin: 0 0 5px 0; display: flex;&quot; data-ke-size=&quot;size16&quot;&gt;  lookahead가 0인 경우&lt;/p&gt;
&lt;!-- 리스트 대신 p 태그로 정리 --&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;1)&amp;nbsp; &amp;nbsp;list에서 '1'이 stack에 push되면 stack의 상태는 ['1']이고 '1'이 '1' ➝ 'N' ➝ 'E' 로 치환될 것이다&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; ▶ stack = ['E']&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;2)&amp;nbsp; &amp;nbsp;list에서 '+'가 stack에 push되면 stack의 상태는 ['E'; '+']이고 치환할 수 있는 기호가 없으므로 다음으로 넘어간다.&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; ▶ stack = ['E'; '+']&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;3)&amp;nbsp; &amp;nbsp;list에서 '3'이 stack에 push되면 stack의 상태는 ['E'; '+'; '3']이고 '3'이 '3' ➝ 'N' ➝ 'E'로 치환될 것이다.&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;▶ stack = ['E'; '+'; 'E'], 이때 'E + E'&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;➝&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;'E'로 치환될 것이다. &lt;br /&gt;&amp;nbsp;▶ stack = ['E'] &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;4)&amp;nbsp; &amp;nbsp;list에서 '*'가 stack에 push되면 stack의 상태는 ['E'; '*']이고 치환할 수 있는 기호가 없으므로 다음으로 넘어간다.&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;▶ stack = ['E'; '*']&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;5)&amp;nbsp; &amp;nbsp;list에서 '5'가 stack에 push되면 stack의 상태는 ['E'; '*'; '5']이고 '5'가 '5' ➝ 'N' ➝ 'E'로 치환될 것이다.&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&amp;nbsp;▶ stack = ['E'; '*'; 'E'], 이때 'E * E'&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;➝&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;'E'로 치환될 것이다.&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;▶ stack = ['E']&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;6)&amp;nbsp; &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;모든 token에 대하여 parsing을 하였을 때, stack에 남아있는 기호가 시작 non-terminal하나만 남았으므로&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; parsing이 성공적으로 끝났다.&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;그러나 연산의 우선순위가 정해지지 않아서 문제가 발생한다. 위 과정을 parse tree로 확인해보면 다음과 같다.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;946&quot; data-origin-height=&quot;441&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oFqC7/btsM1j524r7/IQJYUneLwW6fRfTsZhkwk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oFqC7/btsM1j524r7/IQJYUneLwW6fRfTsZhkwk0/img.png&quot; data-alt=&quot;3 * 2 보다 1 + 3을 먼저 시행하므로 기대값과 계산값이 다를 수 있다.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oFqC7/btsM1j524r7/IQJYUneLwW6fRfTsZhkwk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoFqC7%2FbtsM1j524r7%2FIQJYUneLwW6fRfTsZhkwk0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;508&quot; height=&quot;237&quot; data-origin-width=&quot;946&quot; data-origin-height=&quot;441&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;3 * 2 보다 1 + 3을 먼저 시행하므로 기대값과 계산값이 다를 수 있다.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 lookahead가 필요하다. lookahead를 1로 설정하고 다시 생각해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아까 'lookahead가 0인 경우' 의 3) 단계에서 'E + E' &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;➝&lt;span&gt; 'E'를 그림으로 나타내보자.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;946&quot; data-origin-height=&quot;323&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bolUyZ/btsM1ntQZoz/WTkCBxDcNnO2R9s5iGbPqk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bolUyZ/btsM1ntQZoz/WTkCBxDcNnO2R9s5iGbPqk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bolUyZ/btsM1ntQZoz/WTkCBxDcNnO2R9s5iGbPqk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbolUyZ%2FbtsM1ntQZoz%2FWTkCBxDcNnO2R9s5iGbPqk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;538&quot; height=&quot;184&quot; data-origin-width=&quot;946&quot; data-origin-height=&quot;323&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'E + E' 를 'E' 로 치환하기 전에 '*'를 lookahead로 보고 있으므로, 치환하지 않고 '*'를 stack에 먼저 push한다. 이후 '2'까지 push하고 stack의 값들을 top에서부터 치환하면 다음과 같은 parse tree를 얻을 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;939&quot; data-origin-height=&quot;430&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/clHiyJ/btsM1PxbvzP/HaEixKKego0rWeamnaG35K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/clHiyJ/btsM1PxbvzP/HaEixKKego0rWeamnaG35K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/clHiyJ/btsM1PxbvzP/HaEixKKego0rWeamnaG35K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FclHiyJ%2FbtsM1PxbvzP%2FHaEixKKego0rWeamnaG35K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;507&quot; height=&quot;232&quot; data-origin-width=&quot;939&quot; data-origin-height=&quot;430&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'+' 연산보다 '*' 연산을 먼저 수행하므로 이번 parsing은 문제가 없는 것을 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;no6&quot; style=&quot;padding: 0.4em 1em 0.4em 0.5em; margin: 0.5em 0em; color: #000000; border-left: 10px solid #009a87; border-bottom: 2px #009a87 solid; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;Abstract syntax tree(AST)&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1145&quot; data-origin-height=&quot;347&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Dw56s/btsM14m9OMi/aGK1tQHtnkpi6g2r0vyQr1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Dw56s/btsM14m9OMi/aGK1tQHtnkpi6g2r0vyQr1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Dw56s/btsM14m9OMi/aGK1tQHtnkpi6g2r0vyQr1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDw56s%2FbtsM14m9OMi%2FaGK1tQHtnkpi6g2r0vyQr1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1145&quot; height=&quot;347&quot; data-origin-width=&quot;1145&quot; data-origin-height=&quot;347&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입력 문자열이 들어오면 &quot;Lexical analysis&quot; 단계에서 regular expression을 사용하여 문자열을 token stream으로 변경한다. token stream은 &quot;Syntax analysis&quot;단계에서 CFG에 따라 parsing되고 Abstract Syntax tree(AST)를 만들어낸다. 여기서 AST는 Parse tree와는 다르다.&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;display: flex; gap: 10px; align-items: flex-start;&quot;&gt;
&lt;div style=&quot;flex: 1;&quot;&gt;&lt;figure class=&quot;imageblock undefined&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;231&quot; data-origin-height=&quot;269&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oDZ95/btsM04BMsc9/oBgfGFxDEC8VhZOlKnhcHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oDZ95/btsM04BMsc9/oBgfGFxDEC8VhZOlKnhcHk/img.png&quot; data-alt=&quot;Parse tree&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oDZ95/btsM04BMsc9/oBgfGFxDEC8VhZOlKnhcHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoDZ95%2FbtsM04BMsc9%2FoBgfGFxDEC8VhZOlKnhcHk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;231&quot; height=&quot;269&quot; data-origin-width=&quot;231&quot; data-origin-height=&quot;269&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Parse tree&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;div style=&quot;flex: 1;&quot;&gt;&lt;figure class=&quot;imageblock undefined&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;369&quot; data-origin-height=&quot;177&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Horvz/btsM1rca9xF/I7wclFKFbZRL7sBbbJVsX0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Horvz/btsM1rca9xF/I7wclFKFbZRL7sBbbJVsX0/img.png&quot; data-alt=&quot;Abstract Syntax Tree&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Horvz/btsM1rca9xF/I7wclFKFbZRL7sBbbJVsX0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHorvz%2FbtsM1rca9xF%2FI7wclFKFbZRL7sBbbJVsX0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;369&quot; height=&quot;177&quot; data-origin-width=&quot;369&quot; data-origin-height=&quot;177&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Abstract Syntax Tree&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>CS/프로그래밍언어개론(OCaml)</category>
      <author>PiLove</author>
      <guid isPermaLink="true">https://pi-love0314.tistory.com/20</guid>
      <comments>https://pi-love0314.tistory.com/entry/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D%EC%96%B8%EC%96%B4%EA%B0%9C%EB%A1%A0-Syntax-and-Parsing#entry20comment</comments>
      <pubDate>Tue, 1 Apr 2025 08:50:53 +0900</pubDate>
    </item>
    <item>
      <title>[프로그래밍언어개론] OCaml basic - 3</title>
      <link>https://pi-love0314.tistory.com/entry/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D%EC%96%B8%EC%96%B4%EA%B0%9C%EB%A1%A0-OCaml-basic-3</link>
      <description>&lt;div style=&quot;border: 2px solid #009a87; border-radius: 5px; padding: 15px; box-shadow: 2px 2px 8px text-align: left;&quot;&gt;
&lt;p style=&quot;font-weight: bold; font-size: 20px; color: #009a87;&quot; data-ke-size=&quot;size23&quot;&gt; 목차&lt;/p&gt;
&lt;hr style=&quot;border: 1px solid #009a87; margin: 20px 0; opacity: 0.7;&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;margin: 5px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;color: #00796b; text-decoration: none;&quot; href=&quot;#no0&quot;&gt;➤ Recursive function&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;margin: 5px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;color: #00796b; text-decoration: none;&quot; href=&quot;#no1&quot;&gt;➤ Modules&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;margin: 5px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;color: #00796b; text-decoration: none;&quot; href=&quot;#no2&quot;&gt;➤ Pattern matching&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;margin: 5px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;color: #00796b; text-decoration: none;&quot; href=&quot;#no3&quot;&gt;➤ Type definition&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;no0&quot; style=&quot;padding: 0.4em 1em 0.4em 0.5em; margin: 0.5em 0em; color: #000000; border-left: 10px solid #009a87; border-bottom: 2px #009a87 solid; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Recursive function&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OCaml에서 재귀함수(Recursive function)은 rec 키워드와 함께 named function으로 정의되어야 한다. 아래는 코드 예제이다.&lt;/p&gt;
&lt;pre id=&quot;code_1742219774970&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(* 아래 코드는 rec 키워드 없이 함수가 자기자신을 호출하므로 에러 발생 *)
let mult_all x =
  if x = 1 then 1
  else x * (mult_all (x - 1))
in
Format.printf &quot;Result: %d\n&quot; (mult_all 10)

(* 재귀함수는 아래와 같이 rec 키워드와 함께 사용 *)
let rec mult_all x =
  if x = 1 then 1
  else x * (mult_all (x - 1))
in
Format.printf &quot;Result: %d\n&quot; (mult_all 10)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;no1&quot; style=&quot;padding: 0.4em 1em 0.4em 0.5em; margin: 0.5em 0em; color: #000000; border-left: 10px solid #009a87; border-bottom: 2px #009a87 solid; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Modules&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OCaml에서는 모듈 시스템을 지원한다. 모듈이란 변수, 함수, 타입, 값 등을 그룹화하여 관리하는 단위이다. 이러한 변수, 함수, 타입, 값 등이 모인 모듈이 모여 또다른 모듈을 구성하기도 한다. .ml 파일 또한 여러개의 모듈로 구성된 모듈이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;!-- 특징 박스 --&gt;&lt;/p&gt;
&lt;div style=&quot;border: 2px solid #009a87; border-radius: 5px; padding: 15px; text-align: left;&quot;&gt;&lt;!-- 제목 --&gt;
&lt;p style=&quot;font-weight: bold; font-size: 18px; color: #009a87; margin: 0 0 5px 0; display: flex;&quot; data-ke-size=&quot;size16&quot;&gt;  Modules&lt;/p&gt;
&lt;!-- 리스트 대신 p 태그로 정리 --&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt; &lt;b&gt;각각의 모듈은 자료(변수)와 행동(함수)로 구성&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt; &lt;b&gt;모듈의 이름은 반드시 대문자로 시작&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶operation.ml -&amp;gt; Operation&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; 모듈 내의 변수 또는 함수에 접근 : [module_name].[var_name]&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1742220521183&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(* operation.ml 파일의 내용 *)
let def_val = 99
let add x y = x + y

(* main.ml 파일의 내용 *)
let _ =
  let _ = Format.printf &quot;Result: %d\n&quot; Operation.def_val in
    Format.printf &quot;Result: %d\n&quot; (Operation.add 3 7)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 언급했듯이, 모듈이 모여서 모듈을 구성하기도 한다. 이는 모듈 내부에 모듈이 정의되어 있을 수 있다는 의미이며 이러한 모듈 내부에 정의된 모듈을 Nested module이라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;!-- 특징 박스 --&gt;&lt;/p&gt;
&lt;div style=&quot;border: 2px solid #009a87; border-radius: 5px; padding: 15px; text-align: left;&quot;&gt;&lt;!-- 제목 --&gt;
&lt;p style=&quot;font-weight: bold; font-size: 18px; color: #009a87; margin: 0 0 5px 0; display: flex;&quot; data-ke-size=&quot;size16&quot;&gt;  Nested modules&lt;/p&gt;
&lt;!-- 리스트 대신 p 태그로 정리 --&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  module [module_name] = struct [defs] end definition&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶파일이 곧 모듈이므로, 위 definition으로 생성된 모듈은 nested module이다.&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶module_name : 모듈의 이름이며 만드시 대문자로 시작해야 한다.&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶defs : definition들의 나열이다.&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  Nested 모듈에 접근: [module_name].[nested_module_name].[var_name]&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1742221124103&quot; class=&quot;bash&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;(* operation.ml *)
module IntOp = struct
  let add x y = x + y
end

module FloatOp = struct
  let add x y = x + y
end

(* main.ml *)
let _ =
  let _ = Format.printf &quot;Result: %d\n&quot; (Operation.IntOp.add 3 7) in
  Format.printf &quot;Result: %f\n&quot; (Operation.FloatOp.add 3.0 7.0)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모듈을 open하면 다른 모듈의 변수에 접근할 때 모듈 이름을 생략할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;!-- 특징 박스 --&gt;&lt;/p&gt;
&lt;div style=&quot;border: 2px solid #009a87; border-radius: 5px; padding: 15px; text-align: left;&quot;&gt;&lt;!-- 제목 --&gt;
&lt;p style=&quot;font-weight: bold; font-size: 18px; color: #009a87; margin: 0 0 5px 0; display: flex;&quot; data-ke-size=&quot;size16&quot;&gt;  Module opening&lt;/p&gt;
&lt;!-- 리스트 대신 p 태그로 정리 --&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  open [module_name]: 현 scope에서 모듈 내 변수를 모듈 이름 없이 접근&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶모듈 내의 definition들을 해당 위치에 붙여넣기 한 효과&lt;/p&gt;
&lt;pre id=&quot;code_1742221450727&quot; class=&quot;bash&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(* Operation 모듈 개방 -&amp;gt; Operation 내부의 변수, 함수 등 앞에 &quot;Operation.&quot; 생략하고 접근가능 *)
open Operation

let _ =
  let _ = Format.printf &quot;Result: %d\n&quot; (IntOp.add 3 7) in
  Format.printf &quot;Result: %d\n&quot; (FloatOp.add 3.0 7.0)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나, 위와 같은 방식에는 문제가 있다. 여러 모듈을 open하여 사용할 때, 같은 이름의 변수나 함수가 존재하면 conflict가 발생하게 된다. 아래 예제를 보자.&lt;/p&gt;
&lt;pre id=&quot;code_1742221546448&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;open Operation
open IntOp
open FloatOp

let _ =
  let _ = Format.printf &quot;Result: %d\n&quot; (add 3 7) in
  Format.printf &quot;Result: %d\n&quot; (add 3.0 7.0)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 예제의 경우, IntOp와 FloatOp 두 모듈 모두 add라는 함수가 존재함에도 불구하고, 마지막으로 open된 FloatOp의 add만 사용하게 된다. 결국 FloatOp.add의 인자로 int가 전달되어 컴파일 오류가 발생하게된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;622&quot; data-origin-height=&quot;122&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cL9XY1/btsMOfI2PVH/FuakES8HurkzP66Sdcxi40/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cL9XY1/btsMOfI2PVH/FuakES8HurkzP66Sdcxi40/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cL9XY1/btsMOfI2PVH/FuakES8HurkzP66Sdcxi40/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcL9XY1%2FbtsMOfI2PVH%2FFuakES8HurkzP66Sdcxi40%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;622&quot; height=&quot;122&quot; data-origin-width=&quot;622&quot; data-origin-height=&quot;122&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 경우에는 let - in expression을 사용하여 특정 scope내에서만 모듈을 개방해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;!-- 특징 박스 --&gt;&lt;/p&gt;
&lt;div style=&quot;border: 2px solid #009a87; border-radius: 5px; padding: 15px; text-align: left;&quot;&gt;&lt;!-- 제목 --&gt;
&lt;p style=&quot;font-weight: bold; font-size: 18px; color: #009a87; margin: 0 0 5px 0; display: flex;&quot; data-ke-size=&quot;size16&quot;&gt;  Local module opening&lt;/p&gt;
&lt;!-- 리스트 대신 p 태그로 정리 --&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  let open [module_name] in [expression]&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶module_name: 개방할 모듈 이름&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶expression: 계산할 expression으로 module_name이 개방된 상태에서 계산&lt;/p&gt;
&lt;pre id=&quot;code_1742221706035&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let _ =
  let open Operation.IntOp in
  let _ = Format.printf &quot;Result: %d\n&quot; (add 3 7) in
  let _ = Format.printf &quot;Result: %d\n&quot; (add 1 2) in
  let _ = Format.printf &quot;Result: %d\n&quot; (add 4 12) in
  Format.printf &quot;Result: %d\n&quot; (add 2 5)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모듈의 이름이 긴 경우 약자를 이용하여 모듈을 지칭할 수도 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;!-- 특징 박스 --&gt;&lt;/p&gt;
&lt;div style=&quot;border: 2px solid #009a87; border-radius: 5px; padding: 15px; text-align: left;&quot;&gt;&lt;!-- 제목 --&gt;
&lt;p style=&quot;font-weight: bold; font-size: 18px; color: #009a87; margin: 0 0 5px 0; display: flex;&quot; data-ke-size=&quot;size16&quot;&gt;  Module renaming&lt;/p&gt;
&lt;!-- 리스트 대신 p 태그로 정리 --&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  module [abbreviation] = [module_name]&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶ abbreviation: 모듈의 이름을 지칭할 약자&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶ module_name: 모듈 이름&lt;/p&gt;
&lt;pre id=&quot;code_1742221780835&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;module OI = Operation.IntOp
module F = Format

let _ = F.printf &quot;Result: %d\n&quot; (OI.add 3 7) in
let _ = F.printf &quot;Result: %d\n&quot; (OI.add 1 4) in
let _ = F.printf &quot;Result: %d\n&quot; (OI.add 4 12) in
F.printf &quot;Result: %d\n&quot; (OI.add 2 5)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;no2&quot; style=&quot;padding: 0.4em 1em 0.4em 0.5em; margin: 0.5em 0em; color: #000000; border-left: 10px solid #009a87; border-bottom: 2px #009a87 solid; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Pattern matching&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Pattern matching은 값의 형태에 따라 다른 행동을 수행하게 만드는 expression이다. match - with expression을 사용하며, 그 자체로 하나의 expression이므로 값으로 계산된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;!-- 특징 박스 --&gt;&lt;/p&gt;
&lt;div style=&quot;border: 2px solid #009a87; border-radius: 5px; padding: 15px; text-align: left;&quot;&gt;&lt;!-- 제목 --&gt;
&lt;p style=&quot;font-weight: bold; font-size: 18px; color: #009a87; margin: 0 0 5px 0; display: flex;&quot; data-ke-size=&quot;size16&quot;&gt;  Pattern matching&lt;/p&gt;
&lt;pre id=&quot;code_1742274670100&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;match expression with
| pattern1 -&amp;gt; expression1
| pattern2 -&amp;gt; expression2
...
| patternN -&amp;gt; expressionN&lt;/code&gt;&lt;/pre&gt;
&lt;!-- 리스트 대신 p 태그로 정리 --&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; 코드의 수행 순서&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶expression 계산&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶계산 결과를 pattern1과 매칭&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; - pattern1이 상수인 경우 : expression의 계산 결과와 상수 값이 매칭 확인&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; - pattern1이 변수인 경우 : 변수에 expression의 계산 결과를 바인딩하고 매칭에 항상 성공&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶매칭 성공 시 expression1 실행 or 매칭 실패 시 pattern2와 매칭&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; match - with expression은 하나의 expression이므로 expression1 ~ expressionN까지 동일한 타입을 가짐&lt;/b&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 설명했듯이, pattern에 변수가 들어갈 경우, 변수는 값과 바인딩되고 항상 매칭에 성공한다. 따라서 match with expression이 하나의 값을 보장하기 위해서 마지막 pattern에 변수를 넣어 매칭이 성공됨을 보장하도록 만드는 것이 일반적이다. 아래는 이에 대한 간단한 피보나치 코드 예제이다.&lt;/p&gt;
&lt;pre id=&quot;code_1742274982174&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;module F = Format
module Fib = struct
  let rec fib i =
    match i with
    | 0 -&amp;gt; 0 (* when i is 0 *)
    | 1 -&amp;gt; 1 (* when i is 1 *)
    | n -&amp;gt; fib (n - 2) + fib (n - 1) (* otherwise *)
end

let _ =
  let _ = F.printf &quot;Res: %d\n&quot; (Fib.fib 0) in (* 0 *)
  let _ = F.printf &quot;Res: %d\n&quot; (Fib.fib 1) in (* 1 *)
  let _ = F.printf &quot;Res: %d\n&quot; (Fib.fib 2) in (* 1 *)
  F.printf &quot;Res: %d\n&quot; (Fib.fib 3) (* 2 *)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약, 매칭이 성공됨을 보장하되 값과 바인딩한 변수는 사용하고 싶지 않을 경우에는 wildcard(_)를 사용하면 된다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1742275234471&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let _ =
  let even_or_odd i =
    match i mod 2 with 
    | 0 -&amp;gt; F.printf &quot;Even\n&quot; 
    | 1 -&amp;gt; F.printf &quot;Odd\n&quot; 
    | _ -&amp;gt; F.printf &quot;Unknwon\n&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 만약에 pattern matching의 마지막 pattern에 있는 wildcard를 빼면 컴파일 warning이 발생한다. 따라서 가급적이면 위와 같이 작성하는 것이 좋다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Pattern matching을 사용할 때 &quot;..&quot; 기호를 사용하여 연속된 문자 또는 숫자에 대한 패턴을 생성할 수도 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1742275357273&quot; class=&quot;bash&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;let _ =
  let is_lowercase c =
    match c with
    | 'a' .. 'z' -&amp;gt; true (* when c is 'a' or 'b' or ... or 'z' *)
    | _ -&amp;gt; false
  in
  let _ = F.printf &quot;A : %b\n&quot; (is_lowercase 'A') in (* false *)
  let _ = F.printf &quot;W : %b\n&quot; (is_lowercase 'W') in (* false *)
  let _ = F.printf &quot;b : %b\n&quot; (is_lowercase 'b') in (* true *)
  F.printf &quot;z : %b\n&quot; (is_lowercase 'z') (* true *)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;튜플이나 리스트에 대해서도 패턴 매칭이 가능하다. 아래 코드는 튜플의 첫 번째 값이나 두 번째 값을 반환하는 코드이다.&lt;/p&gt;
&lt;pre id=&quot;code_1742275472563&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let _ =
  let get_fst p =
    match p with (* p is a tuple containig two elements *)
    | (fst, _) -&amp;gt; fst (* fst is a binding occurrence for the first element *)
  in
  let get_snd p =
    match p with (* p is a tuple containig two elements *)
    | (_, snd) -&amp;gt; snd (* snd is a binding occurrence for the second element *)
  in
  let _ = F.printf &quot;fst : %d\n&quot; (get_fst (1, 3)) in (* 1 *)
  let _ = F.printf &quot;fst : %d\n&quot; (get_fst (2, 4)) in (* 2 *)
  let _ = F.printf &quot;snd : %d\n&quot; (get_snd (1, 3)) in (* 3 *)
  F.printf &quot;snd : %d\n&quot; (get_snd (2, 4)) (* 4 *)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 리스트에 대한 패턴 매칭 코드 예제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;no3&quot; style=&quot;padding: 0.4em 1em 0.4em 0.5em; margin: 0.5em 0em; color: #000000; border-left: 10px solid #009a87; border-bottom: 2px #009a87 solid; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Type definition&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OCaml은 사용자가 새로운 타입을 정의하는 것을 허용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;!-- 특징 박스 --&gt;&lt;/p&gt;
&lt;div style=&quot;border: 2px solid #009a87; border-radius: 5px; padding: 15px; text-align: left;&quot;&gt;&lt;!-- 제목 --&gt;
&lt;p style=&quot;font-weight: bold; font-size: 18px; color: #009a87; margin: 0 0 5px 0; display: flex;&quot; data-ke-size=&quot;size16&quot;&gt;  Type definition&lt;/p&gt;
&lt;!-- 리스트 대신 p 태그로 정리 --&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;  type [type_name] = [type]&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶ type_name: 새로운 타입 이름(소문자)&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶ type: 기존 타입&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 string list를 새로운 타입으로 정의하여 사용하는 간단한 코드 예제이다.&lt;/p&gt;
&lt;pre id=&quot;code_1742291531817&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(* string list를 str_list라는 새로운 이름의 타입으로 정의 *)
type str_list = string list

let _ =
  let is_empty (x : str_list) =
    match x with
    | [] -&amp;gt; true
    | _ :: _ -&amp;gt; false
  in
  let _ = F.printf &quot;Res: %b\n&quot; (is_empty []) in
  F.printf &quot;Res: %b\n&quot; (is_empty [&quot;welcome&quot;;&quot;to&quot;;&quot;this&quot;;&quot;class&quot;])&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 타입을 묶어서 타입으로 정의할 수도 있다. 이렇게 정의한 타입을 disjoint union(variant records)라고 부른다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;!-- 특징 박스 --&gt;&lt;/p&gt;
&lt;div style=&quot;border: 2px solid #009a87; border-radius: 5px; padding: 15px; text-align: left;&quot;&gt;&lt;!-- 제목 --&gt;
&lt;p style=&quot;font-weight: bold; font-size: 18px; color: #009a87; margin: 0 0 5px 0; display: flex;&quot; data-ke-size=&quot;size16&quot;&gt;  Disjoint union(Variant records)&lt;/p&gt;
&lt;!-- 리스트 대신 p 태그로 정리 --&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  type [type_name] = [name] (of [type]) | [name] (of [type])&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶ type_name: 새로운 타입 이름(소문자)&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶ name: 식별자(대문자로 시작)&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;- Called &quot;Constructor&quot;&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶ type: 기존 타입&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶ of [type]은 생략가능&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 이에 대한 코드 예제이다.&lt;/p&gt;
&lt;pre id=&quot;code_1742292046648&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;type number =
  | Zero
  | Integer of int
  | Float of float

let _ =
  let x : number = Zero in
  let y : number = Integer 3 in 
  let z : number = Float 3.0 in
  let n_list : number list = [x; y; z] in
  ()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>CS/프로그래밍언어개론(OCaml)</category>
      <author>PiLove</author>
      <guid isPermaLink="true">https://pi-love0314.tistory.com/19</guid>
      <comments>https://pi-love0314.tistory.com/entry/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D%EC%96%B8%EC%96%B4%EA%B0%9C%EB%A1%A0-OCaml-basic-3#entry19comment</comments>
      <pubDate>Tue, 18 Mar 2025 21:45:05 +0900</pubDate>
    </item>
    <item>
      <title>[프로그래밍언어개론] OCaml basic - 2</title>
      <link>https://pi-love0314.tistory.com/entry/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D%EC%96%B8%EC%96%B4%EA%B0%9C%EB%A1%A0-Ocaml-basic-2</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;오늘은 저번 게시글에 이어서 OCaml 언어에 대해 좀 더 알아보는 시간을 가지려고 한다. 목차는 아래와 같다.&lt;/p&gt;
&lt;div style=&quot;border: 2px solid #009a87; border-radius: 5px; padding: 15px; box-shadow: 2px 2px 8px text-align: left;&quot;&gt;
&lt;p style=&quot;font-weight: bold; font-size: 20px; color: #009a87;&quot; data-ke-size=&quot;size23&quot;&gt; 목차&lt;/p&gt;
&lt;p style=&quot;margin: 5px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;color: #00796b; text-decoration: none;&quot; href=&quot;#no0&quot;&gt;➤ Comment&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;margin: 5px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;color: #00796b; text-decoration: none;&quot; href=&quot;#no1&quot;&gt;➤ Standard input/output&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;margin: 5px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;color: #00796b; text-decoration: none;&quot; href=&quot;#no2&quot;&gt;➤ Variables&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;margin: 5px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;color: #00796b; text-decoration: none;&quot; href=&quot;#no3&quot;&gt;➤ let (-in) binding&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;margin: 5px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;color: #00796b; text-decoration: none;&quot; href=&quot;#no4&quot;&gt;➤ &lt;/a&gt;&lt;a style=&quot;color: #00796b; text-decoration: none;&quot; href=&quot;#no5&quot;&gt;Sequencing&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;margin: 5px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;color: #00796b; text-decoration: none;&quot; href=&quot;#no5&quot;&gt;➤ &lt;/a&gt;&lt;a style=&quot;color: #00796b; text-decoration: none;&quot; href=&quot;#no6&quot;&gt;Functions&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;margin: 5px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;color: #00796b; text-decoration: none;&quot; href=&quot;#no6&quot;&gt;➤ Function type&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;margin: 5px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;color: #00796b; text-decoration: none;&quot; href=&quot;#no7&quot;&gt;➤ Tuple &amp;amp; List&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;margin: 5px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;color: #00796b; text-decoration: none;&quot; href=&quot;#no8&quot;&gt;➤ Conditional branch&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;no0&quot; style=&quot;padding: 0.4em 1em 0.4em 0.5em; margin: 0.5em 0em; color: #000000; border-left: 10px solid #009a87; border-bottom: 2px #009a87 solid; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;Comment&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OCaml은 다음과 같은 multiline comment만 지원한다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1742127550024&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(* 주석주석주석주석주석 *)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java의 multiline comment(/* 주석주석주석주석 */) 과 동일하게 동작한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;no1&quot; style=&quot;padding: 0.4em 1em 0.4em 0.5em; margin: 0.5em 0em; color: #000000; border-left: 10px solid #009a87; border-bottom: 2px #009a87 solid; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Standard input/output&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OCaml에는 다양한 입출력 방식이 존재하나, 간단한 형태의 입출력은 다음을 활용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;!-- 특징 박스 --&gt;&lt;/p&gt;
&lt;div style=&quot;border: 2px solid #009a87; border-radius: 5px; padding: 15px; text-align: left;&quot;&gt;&lt;!-- 제목 --&gt;
&lt;p style=&quot;font-weight: bold; font-size: 18px; color: #009a87; margin: 0 0 5px 0; display: flex;&quot; data-ke-size=&quot;size16&quot;&gt;  Standard input/output&lt;/p&gt;
&lt;!-- 리스트 대신 p 태그로 정리 --&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt; &lt;b&gt;Standard input : OCaml의 built-in 함수 readline&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶사용자 입력을 문자열로 반환&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt; &lt;b&gt;Standard output : OCaml의 build-in 모듈 Format&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶모듈 Format에는 출력에 대한 다양한 함수를 지원&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶ &lt;a href=&quot;https://ocaml.org/manual/5.3/api/Format.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://ocaml.org/manual/5.3/api/Format.html&lt;/a&gt; 참고&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 표준 입출력에 대한 간단한 예제코드이다.&lt;/p&gt;
&lt;pre id=&quot;code_1742128420450&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let _ = Format.printf &quot;Input: &quot; in (* Write &quot;Input&quot; on the output buffer *)
let _ = Format.print_flush () in (* Flush the output buffer *)
let x = read_line() in (* Get an input from the user *)
Format.printf &quot;The user input is \&quot;%s\&quot;\n&quot; x (* Write the input on the output buffer *)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;no2&quot; style=&quot;padding: 0.4em 1em 0.4em 0.5em; margin: 0.5em 0em; color: #000000; border-left: 10px solid #009a87; border-bottom: 2px #009a87 solid; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Variables&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OCaml에서 변수(variables)는 특정 값에 묶인(혹은 연결된)(binding) 식별자(identifier)를 나타낸다. &lt;span style=&quot;color: #ee2323;&quot;&gt;다른 언어에서와 달리 변수가 메모리 공간을 가리키는 것이 아니라 변수 자체가 값과 묶이게되는 개념이기 때문에&amp;nbsp;한 번 묶인 변수의 값은 변경 불가능(immutable)하다.&lt;/span&gt; 또한 모든 변수는 선언과 동시에 값에 묶여야만 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변수의 선언 및 묶기(binding)은 let (-in) expression을 사용한다. 아래 코드를 참고하자.&lt;/p&gt;
&lt;pre id=&quot;code_1742128765535&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let x = 3 in (* 변수 선언 및 scope 설정*)
Format.printf &quot;x : %d\n&quot; x&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;let을 통해 x라는 변수에 3이라는 값을 묶었다. 그리고 in을 통하여 x라는 변수의 scope를 설정하였다. scope란 변수를 사용할 수 있는 영역을 의미한다. 해당 영역을 벗어나면 변수 x는 사용이 불가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;no3&quot; style=&quot;padding: 0.4em 1em 0.4em 0.5em; margin: 0.5em 0em; color: #000000; border-left: 10px solid #009a87; border-bottom: 2px #009a87 solid; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;let (-in) binding&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Global let binding은 변수 자체와 값을 연결(binding)하는 definition이다. 값에 이름을 붙인다고 생각하면 이해하기 편하다. 이전 게시글에서 expression은 값을 반환하는 코드 형태라고 설명했었는데, 해당 내용을 기억한 상태로 아래 내용을 보면 이해하기 쉽다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;!-- 특징 박스 --&gt;&lt;/p&gt;
&lt;div style=&quot;border: 2px solid #009a87; border-radius: 5px; padding: 15px; text-align: left;&quot;&gt;&lt;!-- 제목 --&gt;
&lt;p style=&quot;font-weight: bold; font-size: 18px; color: #009a87; margin: 0 0 5px 0; display: flex;&quot; data-ke-size=&quot;size16&quot;&gt;  형태&lt;/p&gt;
&lt;!-- 리스트 대신 p 태그로 정리 --&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt; &lt;u&gt;&lt;b&gt;기본형 : let [variable] = [expression]&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶expression을 계산하고 계산 값을 variable에 바인딩한다.&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶이후 variable이 사용되면 해당 variable을 바인딩된 값으로 치환하여 계산한다.&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶변수 뿐 아니라 이름있는 함수를 정의할 수도 있다.&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶variable 자리에 Wildcard(_)를 사용하여 단순히 expression을 실행하는 용도로도 활용한다.&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;(OCaml에서는 사용하지 않는 값을 변수에 바인딩 하는 것을 금지)&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt; &lt;u&gt;&lt;b&gt;기본형 : let [variable] = [expression1] in [expression2]&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶expression1을 계산하고 계산 값을 variable에 바인딩한다.&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶expression2를 계산하고 계산한 결과값을 반환한다.&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶이 때, variable이 사용되면 해당 variable을 바인딩 된 값으로 치환하여 계산한다.&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶결국, 그 자체로 하나의 expression이므로 expression2의 값을 반환한다.&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 let binding과 let-in binding 코드 예제이다.&lt;/p&gt;
&lt;pre id=&quot;code_1742130803178&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let x = 3 (* 3을 x에 바인딩 *)
Format.printf &quot;x : %d&quot;, x (* x에 바인딩된 값 3으로 치환되어 계산 *)
(* 
   바로 위의 코드는 expression이므로 값을 반환한다. 
   하지만 그 값을 사용하지 않기에 아래와 같이 수정해야 한다. 
 *)
let _ = Format.printf &quot;x : %d&quot;, x


let x = 3 in let y = 1 in x + y
(* 
   1) x에 3이 바인딩되어 (let y = 1 in x + y)에서 사용된다. 
   2) y에 1이 바인딩 되어 (x + y)에 사용된다.
   3) 전체 코드 자체가 expression이므로 x + y 결과 값(4)을 반환한다.
 *)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;no4&quot; style=&quot;padding: 0.4em 1em 0.4em 0.5em; margin: 0.5em 0em; color: #000000; border-left: 10px solid #009a87; border-bottom: 2px #009a87 solid; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Sequencing&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OCaml에서의 sequencing은 연속적인 &lt;b&gt;unit expression&lt;/b&gt;의 계산을 수행한다. 여기서 unit expression이란&lt;span style=&quot;color: #ee2323;&quot;&gt; unit 타입을 반환하는 expression&lt;/span&gt;을 의미한다. 이전 게시글에서 살펴보았듯이, unit타입은 값이 없는 것을 의미한다. 따라서 &lt;span style=&quot;color: #ee2323;&quot;&gt;unit expression은 연산을 수행하지만, 반환값이 필요없는 expression&lt;/span&gt;을 의미한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;이러한 unit expression을 연속적으로 수행하게 될 경우, 반환된 값 unit에 대해 어떤 처리도 하지 않았기 때문에 OCaml에서는 오류나 경고를 준다&lt;span style=&quot;color: #000000;&quot;&gt;. 따라서, 모든 unit expression에 대한 처리가 필요한데, 이는 wildcard를 이용하거나 sequencing을 이용하여 처리할 수 있다. 아래 예제를 보자.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1742132307665&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(* Sequencing 사용 *)
Format.printf &quot;1\n&quot;;
Format.printf &quot;2\n&quot;;
Format.printf &quot;3\n&quot;

(* Wildcard 사용 *)
let _ = Format.printf &quot;1\n&quot;
let _ = Format.printf &quot;2\n&quot;
let _ = Format.printf &quot;3\n&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 sequencing을 사용할 땐, 아래와 같이 begin-end expression을 함께 사용하여 명시적으로 sequencing을 표기하는 것이 일반적이다. begin-end expression은 괄호 (...)와 동일한 효과이다.&lt;/p&gt;
&lt;pre id=&quot;code_1742132382181&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;begin
  Format.printf &quot;1\n&quot;;
  Format.printf &quot;2\n&quot;;
  Format.printf &quot;3\n&quot;
end&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;no5&quot; style=&quot;padding: 0.4em 1em 0.4em 0.5em; margin: 0.5em 0em; color: #000000; border-left: 10px solid #009a87; border-bottom: 2px #009a87 solid; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Functions&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전 게시글에서 알아보았듯이 OCaml에서 함수는 first-class value이다. first-class value의 특징은 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;!-- 특징 박스 --&gt;&lt;/p&gt;
&lt;div style=&quot;border: 2px solid #009a87; border-radius: 5px; padding: 15px; text-align: left;&quot;&gt;&lt;!-- 제목 --&gt;
&lt;p style=&quot;font-weight: bold; font-size: 18px; color: #009a87; margin: 0 0 5px 0; display: flex;&quot; data-ke-size=&quot;size16&quot;&gt;  First-class function&lt;/p&gt;
&lt;!-- 리스트 대신 p 태그로 정리 --&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt; &lt;b&gt;함수 자체가 expression&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶함수를 변수에 할당할 수 있다.&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶함수를 다른 &lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;&lt;span&gt;함수의 인자로 전달할 수 있다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶함수가 다른 &lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;&lt;span&gt;함수의 반환값이 될 수 있다.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt; &lt;b&gt;기본형 : fun [param_list] -&amp;gt; [expression] &lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶param_list: 인자가 바인딩 될 변수들의 나열 (띄어쓰기로 구분)&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶&lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;&lt;span&gt;&lt;span&gt;expression: 함수의 몸체이며, 해당 expression의 계산 결과가 곧 return value &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 fun을 이용해서 이름있는 함수를 정의하는 것은 불가능하다. 오로지 익명(anonymous) 함수만을 정의할 수 있다. 아래 코드를 확인하자.&lt;/p&gt;
&lt;pre id=&quot;code_1742172895970&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(* anonymous함수 정의 *)
fun x -&amp;gt; x + 1
(* anonymous함수를 변수에 바인딩 했을 뿐, 여전히 함수의 이름은 없음 *)
let x = (fun x -&amp;gt; x + 1) in
Format.printf &quot;result : %d&quot; (x 3)

(* 여러개의 파라미터는 아래와 같이 뛰어쓰기로 구분 *)
let f = (fun x y -&amp;gt; x + y) in
Format.printf &quot;result : %d&quot; (f 3 5)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면, 이름있는 함수를 정의하는 방법은 무엇일까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바로, let definition 혹은 let -in expression을 활용하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;!-- 특징 박스 --&gt;&lt;/p&gt;
&lt;div style=&quot;border: 2px solid #009a87; border-radius: 5px; padding: 15px; text-align: left;&quot;&gt;&lt;!-- 제목 --&gt;
&lt;p style=&quot;font-weight: bold; font-size: 18px; color: #009a87; margin: 0 0 5px 0; display: flex;&quot; data-ke-size=&quot;size16&quot;&gt;  이름있는 함수의 정의&amp;nbsp;&lt;/p&gt;
&lt;!-- 리스트 대신 p 태그로 정리 --&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; 기본형 : let [id] [param_list] = [expression] &lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶id: 함수 이름&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶param_list: 인자가 바인딩 될 변수들의 나열 (띄어쓰기로 구분)&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶expression: 함수 몸체&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; 기본형 : let [id] [param_list] = [expression1] in [expression2] &lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶id: 함수 이름&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶param_list: 인자가 바인딩 될 변수들의 나열 (띄어쓰기로 구분)&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶expression1: 함수 몸체&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶expression2: 함수 정의 후 실행할 expression&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이름있는 함수를 정의하고 해당 함수를 사용하는 방식은 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;익명함수를 정의하고 변수에 할당하여 해당 변수를 사용하는 방식과&lt;/span&gt; 동일한 동작을 수행한다. 아래는 코드예제이다.&lt;/p&gt;
&lt;pre id=&quot;code_1742173427732&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(* 익명함수를 정의하고 변수에 바인딩 *)
let sum = fun x y -&amp;gt; x + y
let _ = Format.printf &quot;Result: %d\n&quot; (sum 3 7)

let sum = fun x y -&amp;gt; x + y in
Format.printf &quot;Result: %d\n&quot; (sum 3 7)

(* ---------------------------------------- *)

(* 위 코드와 동일하게 동작함 *)
(* 이름있는 함수를 정의하고 사용 *)
let sum x y = x + y
let _ = Format.printf &quot;Result: %d\n&quot; (sum 3 7)

let sum x y = x + y in
Format.printf &quot;Result: %d\n&quot; (sum 3 7)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;no6&quot; style=&quot;padding: 0.4em 1em 0.4em 0.5em; margin: 0.5em 0em; color: #000000; border-left: 10px solid #009a87; border-bottom: 2px #009a87 solid; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Function type&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수의 타입은 arrow 형태로 표기한다.&lt;span style=&quot;color: #ee2323;&quot;&gt; (type1 &amp;rarr; type2)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;type1은 파라미터의 type을 의미하며, type2는 함수 몸체 expression의 type을 의미한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 파라미터를 받는 경우, curried form으로 표기한다. curried form이란 여러개의 인자를 파라미터로 받는 경우, 순차적으로 표기하는 형태이다. 예를 들어 int type의 파라미터를 2개 받으면 int &amp;rarr; int &amp;rarr; type2 로 표기한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 예제를 보자. 주석을 제대로 이해하는 것이 중요하다.&lt;/p&gt;
&lt;pre id=&quot;code_1742173903700&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(* inc : int -&amp;gt; int *)
let inc x = x + 1

(* sum : int -&amp;gt; int -&amp;gt; int *)
let sum x y = x + y

let sum x y = x + y in (* sum : int -&amp;gt; int -&amp;gt; int *)
let sum' = sum 1 in 
(* 
  sum' : int -&amp;gt; int
  원래 sum이 int &amp;rarr; int &amp;rarr; int 이지만,
  sum'에서 인자로 1 하나만 넘기고 있다.
  따라서, sum 1의 연산 결과인 y &amp;rarr; y + 1이 새로운 함수가 된다.
  이를 sum 1에 대입하면 let sum' = y &amp;rarr; y + 1 in 이 되므로
  sum'의 type : int &amp;rarr; int
*)

let res = sum' 3 in 
(*
  res : int
  sum'에서 설명한 주석을 이해했다면, res의 type이 왜 int 인지 쉽게 이해가 가능하다.
  sum'은 y &amp;rarr; y + 1 인데, 여기에 3을 넘겼으므로 4라는 상수 함수가 된다.
  이 결과를 sum' 3에 대입하면, let rest = 4 in 이 되므로
  rest의 type : int
*)

Format.printf &quot;Result: %d\n&quot; res (* the result is 4 *)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;no7&quot; style=&quot;padding: 0.4em 1em 0.4em 0.5em; margin: 0.5em 0em; color: #000000; border-left: 10px solid #009a87; border-bottom: 2px #009a87 solid; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Tuple &amp;amp; List&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Tuple은 연속된 값을 저장하는 자료구조이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;!-- 특징 박스 --&gt;&lt;/p&gt;
&lt;div style=&quot;border: 2px solid #009a87; border-radius: 5px; padding: 15px; text-align: left;&quot;&gt;&lt;!-- 제목 --&gt;
&lt;p style=&quot;font-weight: bold; font-size: 18px; color: #009a87; margin: 0 0 5px 0; display: flex;&quot; data-ke-size=&quot;size16&quot;&gt;  Tuple&lt;/p&gt;
&lt;!-- 리스트 대신 p 태그로 정리 --&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt; &lt;b&gt;기본형 : any1, any2, any3 or (any1, any2, any3)&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶쉼표를 사용하여 생성한다.&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt; &lt;b&gt;서로 다른 타입을 하나의 tuple에 저장할 수도 있다&lt;/b&gt;.&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶ex) 0, (1, 2, 3, 'c', &quot;hi&quot;)&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt; &lt;b&gt;Tuple의 타입은 *를 사용하여 표기한다.&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶ex) 0, (1, &quot;hi&quot;) : int * (int * string)&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;/&amp;nbsp; &amp;nbsp; &amp;nbsp;튜플에 괄호를 사용했을 경우, 타입을 표기할 때도 괄호 사용&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; let 또는 let - in으로 tuple의 각 원소를 변수에 바인딩 할 수 있다.&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶ex) let x, y = (1, 3)&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;List는 tuple과 다르게 모든 원소의 타입이 동일하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;!-- 특징 박스 --&gt;&lt;/p&gt;
&lt;div style=&quot;border: 2px solid #009a87; border-radius: 5px; padding: 15px; text-align: left;&quot;&gt;&lt;!-- 제목 --&gt;
&lt;p style=&quot;font-weight: bold; font-size: 18px; color: #009a87; margin: 0 0 5px 0; display: flex;&quot; data-ke-size=&quot;size16&quot;&gt;  List&lt;/p&gt;
&lt;!-- 리스트 대신 p 태그로 정리 --&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; 기본형 : [1; 2; 3; 4]&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶대괄호([])로 리스트 생성&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;▶세미콜론으로 원소 구분&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; 리스트의 타입 표기 : [type] list&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶type : 원소의 타입&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶ex) int list&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; 연산자 '::'&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶리스트 앞에 원소를 삽입하여 &lt;span style=&quot;color: #ee2323;&quot;&gt;새로운&lt;/span&gt; 리스트 반환&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶ex) 0 :: [1; 2; 3]&amp;nbsp; --&amp;gt; [0; 1; 2; 3]&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; 연산자 '@'&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶두 리스트를 연결하여&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;새로운&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;리스트 반환&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶ex) [1; 2; 3] @ [4; 5; 6]&amp;nbsp; --&amp;gt; [1; 2; 3; 4; 5; 6]&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OCaml은 List에 대한 내장 라이브러리를 지원하는데, 아래는 자주 사용하게 될 함수이니 참고하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;!-- 특징 박스 --&gt;&lt;/p&gt;
&lt;div style=&quot;border: 2px solid #009a87; border-radius: 5px; padding: 15px; text-align: left;&quot;&gt;&lt;!-- 제목 --&gt;
&lt;p style=&quot;font-weight: bold; font-size: 18px; color: #009a87; margin: 0 0 5px 0; display: flex;&quot; data-ke-size=&quot;size16&quot;&gt;  Library for List&lt;/p&gt;
&lt;!-- 리스트 대신 p 태그로 정리 --&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; List.map [function] [list]&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶list에 존재하는 모든 원소에 대하여 function 수행 후 &lt;span style=&quot;color: #ee2323;&quot;&gt;새로운&lt;/span&gt; 리스트 반환&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶type : ('a -&amp;gt; 'b) -&amp;gt; 'a list -&amp;gt; 'b list&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; ('a -&amp;gt; 'b)는 파라미터로 받은 함수의 타입을 의미한다.&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; -&amp;gt; 'a list는 파라미터로 받은 리스트의 타입을 의미한다.&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; -&amp;gt; 'b list는 List.map의 수행 결과의 타입을 의미한다.&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; List.fold_left [function] [init] [list]&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶list에 존재하는 모든 원소에 대하여 왼쪽 원소부터 init과 function 수행한 후 &lt;span style=&quot;color: #ee2323;&quot;&gt;누적 값&lt;/span&gt; 계산&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶type : ('b -&amp;gt; 'a -&amp;gt; 'b) -&amp;gt; 'b -&amp;gt; 'a list -&amp;gt; 'b&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; ('b -&amp;gt; 'a -&amp;gt; 'b)는 파라미터로 받은 함수의 타입을 의미한다.&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; -&amp;gt; 'b는 init의 타입을 의미한다.&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; -&amp;gt; 'a list는 파라미터로 받은 리스트의 타입을 의미한다.&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; -&amp;gt; 'b는 List.fold_left의 수행 결과의 타입을 의미한다.&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt; &lt;a href=&quot;https://caml.inria.fr/pub/docs/manual-ocaml/libref/List.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://caml.inria.fr/pub/docs/manual-ocaml/libref/List.html&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;no8&quot; style=&quot;padding: 0.4em 1em 0.4em 0.5em; margin: 0.5em 0em; color: #000000; border-left: 10px solid #009a87; border-bottom: 2px #009a87 solid; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Co&lt;/b&gt;&lt;b&gt;nditional branch&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;if - then - else expression을 통해 분기문을 작성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;!-- 특징 박스 --&gt;&lt;/p&gt;
&lt;div style=&quot;border: 2px solid #009a87; border-radius: 5px; padding: 15px; text-align: left;&quot;&gt;&lt;!-- 제목 --&gt;
&lt;p style=&quot;font-weight: bold; font-size: 18px; color: #009a87; margin: 0 0 5px 0; display: flex;&quot; data-ke-size=&quot;size16&quot;&gt;  if - then - else&lt;/p&gt;
&lt;!-- 리스트 대신 p 태그로 정리 --&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;  기본형 : if [expression1] then [expression2] else [expression3]&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶Expression1 을 계산&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; (Expression1은 반드시 bool 타입)&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;▶계산된 결과가 true인 경우, expression2를 계산하고 이 결과가 전체 expression의 값 &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;&lt;span&gt; &lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;▶&lt;/span&gt;계산된 결과가 false인 경우, expression3을 계산하고 이 결과가 전체 expression의 값 &lt;/span&gt;&lt;/span&gt; &amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;if - then - else도 그 자체로 expression이므로, 하나의 값으로 계산된다. 즉, 값을 반환하는 expression이다. 이러한 expression은 항상 하나의 타입을 가져야 하므로, &lt;span style=&quot;color: #ee2323;&quot;&gt;expression2와 expression3에나 같은 타입의 expression이 위치&lt;/span&gt;해야만 한다. if - then - else 전체의 타입을 통일해야 하기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 해당 내용을 포함한 코드 예제이다.&lt;/p&gt;
&lt;pre id=&quot;code_1742175770902&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;let is_odd x =
if x mod 2 = 0 then false (* bool *)
else 0 (* int *)
in
Format.printf &quot;Res: %b\n&quot; (is_odd 3)

(* 
  위 코드는 에러가 발생한다.
  expression2와 expression3의 타입이 동일하지 않기 때문이다.
  따라서 아래 코드와 같이 수정해줘야 한다.
*)

let is_odd x =
if x mod 2 = 0 then false (* bool *)
else true (* bool *)
in
Format.printf &quot;Res: %b\n&quot; (is_odd 3)&lt;/code&gt;&lt;/pre&gt;</description>
      <category>CS/프로그래밍언어개론(OCaml)</category>
      <author>PiLove</author>
      <guid isPermaLink="true">https://pi-love0314.tistory.com/18</guid>
      <comments>https://pi-love0314.tistory.com/entry/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D%EC%96%B8%EC%96%B4%EA%B0%9C%EB%A1%A0-Ocaml-basic-2#entry18comment</comments>
      <pubDate>Mon, 17 Mar 2025 10:44:02 +0900</pubDate>
    </item>
    <item>
      <title>[프로그래밍언어개론] OCaml basic - 1</title>
      <link>https://pi-love0314.tistory.com/entry/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D%EC%96%B8%EC%96%B4%EA%B0%9C%EB%A1%A0-Ocaml-1-1</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div style=&quot;border: 2px solid #009a87; border-radius: 5px; padding: 15px; box-shadow: 2px 2px 8px text-align: left;&quot;&gt;
&lt;p style=&quot;font-weight: bold; font-size: 20px; color: #009a87;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt; 목차&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;margin: 5px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;color: #00796b; text-decoration: none;&quot; href=&quot;#no0&quot;&gt;➤ OCaml?&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;margin: 5px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;color: #00796b; text-decoration: none;&quot; href=&quot;#no1&quot;&gt;➤ Primitive types&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;margin: 5px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;color: #00796b; text-decoration: none;&quot; href=&quot;#no2&quot;&gt;➤ Basic compilation using Dune&lt;/a&gt;&lt;/p&gt;
&lt;p style=&quot;margin: 5px 0;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;color: #00796b; text-decoration: none;&quot; href=&quot;#no3&quot;&gt;➤ Statement? Expression?&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;no0&quot; style=&quot;padding: 0.4em 1em 0.4em 0.5em; margin: 0.5em 0em; color: #000000; border-left: 10px solid #009a87; border-bottom: 2px #009a87 solid; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Ocaml?&lt;/b&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;OCaml은 Caml에 객체지향(OOP)개념을 추가하여 확장한 프로그래밍 언어이다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;아래는 OCaml언어의 대표적인 특징이다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;!-- 특징 박스 --&gt;&lt;/p&gt;
&lt;div style=&quot;border: 2px solid #009a87; border-radius: 5px; padding: 15px; text-align: left;&quot;&gt;&lt;!-- 제목 --&gt;
&lt;p style=&quot;font-weight: bold; font-size: 18px; color: #009a87; margin: 0 0 5px 0; display: flex;&quot; data-ke-size=&quot;size16&quot;&gt;  특징&lt;/p&gt;
&lt;!-- 리스트 대신 p 태그로 정리 --&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  &lt;span style=&quot;text-align: start;&quot;&gt;Functional programming language&lt;/span&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;▶ &lt;span style=&quot;text-align: start;&quot;&gt;함수는 first-class values (함수도 변수처럼 사용 가능하다)&lt;/span&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  &lt;span style=&quot;text-align: start;&quot;&gt;Strongly typed language&lt;/span&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;▶ &lt;span style=&quot;text-align: start;&quot;&gt;모든 변수 및 표현식의 타입은 컴파일 시점에 결정&lt;/span&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  &lt;span style=&quot;text-align: start;&quot;&gt;Type inference&lt;/span&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;▶ &lt;span style=&quot;text-align: start;&quot;&gt;타입 시스템이 변수 및 표현식의 타입을 추론&lt;/span&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  &lt;span style=&quot;text-align: start;&quot;&gt;Polymorphism&lt;/span&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;▶ &lt;span style=&quot;text-align: start;&quot;&gt;데이터 구조 및 알고리즘을 일반적으로 구현&lt;/span&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  &lt;span style=&quot;text-align: start;&quot;&gt;Pattern matching&lt;/span&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;▶ &lt;span style=&quot;text-align: start;&quot;&gt;Case 분석 지원&lt;/span&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;  &lt;span style=&quot;text-align: start;&quot;&gt;Module system&lt;/span&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: start;&quot;&gt; &lt;span style=&quot;color: #000000; text-align: left;&quot;&gt;▶&lt;/span&gt; 프로그램을 여러 모듈로 나누어 구현&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;no1&quot; style=&quot;padding: 0.4em 1em 0.4em 0.5em; margin: 0.5em 0em; color: #000000; border-left: 10px solid #009a87; border-bottom: 2px #009a87 solid; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Primitive types&lt;/b&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;1. unit&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;unit 타입은 &quot;()&quot; 하나로 구성된 singleton 집합이다. &quot;아무것도 없음&quot;을 나타내는 값으로 C/C++, Java의 void타입과 유사하다.&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&amp;nbsp;OCaml의 모든 표현식은 반드시 값으로 계산되고 존재&lt;/span&gt;한다. 따라서&amp;nbsp;&lt;span style=&quot;color: #ee2323;&quot;&gt;C/C++, Java의 void와는 다르게 unit이 반환되면 &quot;아무것도 없음&quot;을 나타내는 값이 반환된 것&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이다. C/C++, Java의 void처럼 아무것도 반환하지 않는 것이 아니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;() 값을 통해 &quot;아무것도 없음&quot; 을 표현한다는 것을 기억하면 좋을 것 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;2. Int&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;int 타입은 모든 정수의 집합이다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;3. float&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;float 타입은 모든 실수의 집합이다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;4. char&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;char 타입은 모든 문자의 집합이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;5. bool&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;bool 타입은 true와 false로 이루어진 집합이다. 여기서 조심해야 할 부분이 있다. 아래 그림을 확인해보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;798&quot; data-origin-height=&quot;162&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfWByy/btsMLPRbegi/nEPS9fDGHrmnWHURkyfLjk/tfile.dat&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfWByy/btsMLPRbegi/nEPS9fDGHrmnWHURkyfLjk/tfile.dat&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfWByy/btsMLPRbegi/nEPS9fDGHrmnWHURkyfLjk/tfile.dat&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfWByy%2FbtsMLPRbegi%2FnEPS9fDGHrmnWHURkyfLjk%2Ftfile.dat&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;798&quot; height=&quot;162&quot; data-origin-width=&quot;798&quot; data-origin-height=&quot;162&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;위 그림을 보면, 같은 값을 가지는 List에 대해 '='와 '=='의 결과가 다른 것을 확인할 수 있다. 그 이유는&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;OCaml의 '='는 structural equality(구조적 동등성)을 확인하고 '=='는 physical equality(물리적 동등성)을 확인&lt;/span&gt;하기 때문이다. 따라서, '='의 &lt;span style=&quot;color: #000000;&quot;&gt;경우 비교하는 두 리스트의 값이 같기 때문에 true를 반환하고, '=='의 경우 두 리스트의 물리적인 주소, 즉 두 리스트 자체가 서로 같은 지를 검사하기 때문에 false를 반환하는 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;no2&quot; style=&quot;padding: 0.4em 1em 0.4em 0.5em; margin: 0.5em 0em; color: #000000; border-left: 10px solid #009a87; border-bottom: 2px #009a87 solid; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Basic compilation using Dune&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &lt;b&gt;1. Dune?&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Dune이란, C/C++의 Makefile과 같이 OCaml 프로젝트를 쉽게 컴파일하고 실행할 수 있도록 도와주는 빌드 시스템이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;2. How to use?&lt;/b&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Dune을 사용하여 프로그램을 컴파일하는 기본적인 방법은 다음과 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;우선 실행하고자 하는 파일 디렉토리 내에 dune 파일을 생성한 후, 아래와 같이 작성한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1741962607662&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;(inclue_subdirs unqualified)
(excutable (name hello_world))&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: left;&quot;&gt; ▶ (inclue_subdirs unqualified) :&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: left;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;현재 디렉토리를 포함하여 하위 디렉토리의 모든 소스파일을 하나의 프로젝트 코드처럼 간주한다는 의미이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: left;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;좀 더 쉽게 말하자면, 현재 디렉토리 아래의 모든 .ml파일들을 하나의 폴더 안에 있는 것처럼 취급한다는 의미이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: left;&quot;&gt; ▶ (excutable (name hello_world)) :&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: left;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;hello_world.ml 파일을 프로그램의 entry point(다른 언어의 표현으로 main)로 간주하고,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: left;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;실행가능한 바이너리 파일로 컴파일한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이렇게 작성한 dune 파일에 대하여 아래 명령어를 실행하면 hello_world.ml 파일을 .exe 파일로 컴파일 할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1741962633737&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;dune build hello_world.exe&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;명령어 실행 후, 디렉토리의 파일 구조를 살펴보면 다음과 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;424&quot; data-origin-height=&quot;362&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cEySZg/btsMKHNUuOb/S9kkTb8V16K6yUrIkLJaO0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cEySZg/btsMKHNUuOb/S9kkTb8V16K6yUrIkLJaO0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cEySZg/btsMKHNUuOb/S9kkTb8V16K6yUrIkLJaO0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcEySZg%2FbtsMKHNUuOb%2FS9kkTb8V16K6yUrIkLJaO0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;300&quot; height=&quot;256&quot; data-origin-width=&quot;424&quot; data-origin-height=&quot;362&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이렇게 생성된 실행파일(hello_world.exe)을 실행하기 위해서는 아래 명령어를 한번 더 작성해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1741963222083&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;_build/default/hello_world.exe&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;그러나 위와 같은 방식은 (compile -&amp;gt; execute) 과정을 두 번에 나누어서 진행하기 때문에 코드를 수정할 때마다 두 번의 명령어를 작성해야 한다. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;따라서 코드를 수정해야 할 일이 많을 경우, exec이라는 명령어를 활용한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1741963458294&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;dune exec ./hello_world.exe&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;exec 명령어를 수행하면 (compile -&amp;gt; execute) 과정을 한 번에 진행하기 때문에 좀 더 편하게 사용 가능하다. 물론, 시간은 더 오래 걸릴 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;no3&quot; style=&quot;padding: 0.4em 1em 0.4em 0.5em; margin: 0.5em 0em; color: #000000; border-left: 10px solid #009a87; border-bottom: 2px #009a87 solid; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Statement? Expression?&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;Statement? Expression?&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Statement(구문)와 Expression(표현식)은 프로그래밍 언어의 구성 요소이다. 언어에 따라 statement와 expression이 명확하게 분리되지 않는 경우도 존재하지만 우선 일반적인 경우를 확인해보자.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;!-- 특징 박스 --&gt;&lt;/p&gt;
&lt;div style=&quot;border: 2px solid #009a87; border-radius: 5px; padding: 15px; text-align: left;&quot;&gt;&lt;!-- 제목 --&gt;
&lt;p style=&quot;font-weight: bold; font-size: 18px; color: #009a87; margin: 0 0 5px 0; display: flex;&quot; data-ke-size=&quot;size16&quot;&gt;  Feature of (Statement &amp;amp; Expression)&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;!-- 리스트 대신 p 태그로 정리 --&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt; Statement&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶프로그램의 동작을 수행하는 코드이다. 값을 반환하지 않는 코드라고 이해하면 편하다.&lt;/p&gt;
&lt;p style=&quot;padding: 5px;&quot; data-ke-size=&quot;size16&quot;&gt; Expression&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶값으로써 계산되는 코드이며, 값을 반환하는 코드이다.&lt;/p&gt;
&lt;p style=&quot;padding-left: 27px;&quot; data-ke-size=&quot;size16&quot;&gt;▶실행 전과 실행 후의 메모리 상태가 동일하다.&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Expression의 특징을 살펴 보면 &quot;실행 전과 실행 후의 메모리 상태가 동일하다&quot; 라는 특징이 있다. OCaml의 변수는 기본적으로 &lt;span style=&quot;color: #ee2323;&quot;&gt;Immutable(불변성)한 특성&lt;/span&gt;을 가지고 있다. 따라서, OCaml의 대부분의 코드들은 expression으로 이루어져 있다. 그렇다고 해서 OCaml이 expression으로만 구성되는 pure functional language(순수 함수형 언어)인 것은 아니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;다음 게시글에서는 OCaml의 comment, I/O, variable, function, let-in 등등 OCaml언어의 기본적인 내용들을 알아보자.&lt;/span&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>CS/프로그래밍언어개론(OCaml)</category>
      <author>PiLove</author>
      <guid isPermaLink="true">https://pi-love0314.tistory.com/16</guid>
      <comments>https://pi-love0314.tistory.com/entry/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D%EC%96%B8%EC%96%B4%EA%B0%9C%EB%A1%A0-Ocaml-1-1#entry16comment</comments>
      <pubDate>Sat, 15 Mar 2025 10:18:14 +0900</pubDate>
    </item>
  </channel>
</rss>