<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>flower-in-eyes.log</title>
        <link>https://velog.io/</link>
        <description>난민</description>
        <lastBuildDate>Mon, 14 Jul 2025 21:34:02 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>flower-in-eyes.log</title>
            <url>https://velog.velcdn.com/images/flower-in-eyes/profile/a6b89240-e483-4bbd-bc14-559820ea003d/image.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. flower-in-eyes.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/flower-in-eyes" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[혼공분석] 2주차]]></title>
            <link>https://velog.io/@flower-in-eyes/%ED%98%BC%EA%B3%B5%EB%B6%84%EC%84%9D-2%EC%A3%BC%EC%B0%A8</link>
            <guid>https://velog.io/@flower-in-eyes/%ED%98%BC%EA%B3%B5%EB%B6%84%EC%84%9D-2%EC%A3%BC%EC%B0%A8</guid>
            <pubDate>Mon, 14 Jul 2025 21:34:02 GMT</pubDate>
            <description><![CDATA[<h1 id="데이터-수집하기">데이터 수집하기</h1>
<h2 id="학습목표">학습목표</h2>
<ol>
<li>api로 가져오는 법</li>
<li>웹스크래핑으로 가져오는법</li>
</ol>
<h2 id="02-1-api-사용하기">02-1 API 사용하기</h2>
<h3 id="api-줄임말-뜻-핵심은-예시는">api 줄임말 뜻? 핵심은? 예시는?</h3>
<ul>
<li>Application Programming Interface 라는 거창한 명칭이다. 어플리케이션은 프로그래밍 규약인데, 사실 api가 아키텍쳐 설계도는 아니다. 요즘 날에 쓰이는 용어로는, 그니까 이걸 어떻게 사용하면 되고 무슨 기능을 제공할 수 있는데? 라는걸 표현하는 문서지. 세세한 세팅환경까지 전부 명세하는 규약은 아니라는것. </li>
</ul>
<h4 id="web-api란">web API란?</h4>
<ul>
<li>웹 앱 API를 말하는거지. 웹앱은 이렇게 만드세요. 가 아니라, 이제는 REST API를 표현하는 말로 변모됨.</li>
</ul>
<h4 id="http란">HTTP란?</h4>
<ul>
<li>HyperText Transfer Protocol</li>
<li>초월문서 전송 규약</li>
<li>HTTP는 그런 방법론이자 기술이다. 그런데 이 기술을 반드시 사용하고 아니 요즘은 이제 이거를 전용으로 이 기술이 사용된다. 바로 브라우저와 웹앱 사이에 데이터 전송 방식이 HTTP로 자리 잡았다. </li>
</ul>
<h4 id="그-두개가-뭔-차이일까-api를-어디까지-api로-봐야될까">그 두개가 뭔 차이일까? API를 어디까지 API로 봐야될까?</h4>
<ul>
<li>HTTP는 말그대로 기술이고, API는 그래서 어떻게 사용하면 되는데? 이다. 웹 API만 있는게 아니다. embed program api 혹은 라이브러리 api 혹은 프레임워크 api 혹은 엔진 api 등 결국 어플리케이션 간에 소통을 위한 방법이 api이기 때문에 둘은 다르다.</li>
</ul>
<h3 id="rest-api란-일단-rest가-뭐의-줄임말이야-그게-뭔뜻이야">REST API란? 일단 REST가 뭐의 줄임말이야? 그게 뭔뜻이야?</h3>
<ul>
<li>REpresentational State Transfer</li>
<li>아 계속해서 검색해가며 하는데 확실하게 정리하면 왜 이게 Representational State Transfer냐면, State를 전송할때 대표적인 State만 전송하자 해서 State Transfer인데 Representational 이라는 수식어가 붙는다.</li>
<li>브라우저에서 요청한 주소를 매핑할때 서버에서 어떤 주소를 받아들일때 동작하게 만들지를 설계할때 아주 대표적인 &#39;리소스&#39;만 받아도 충분히 동작할 수 있다는 근거로 등장한다.</li>
<li>왜냐? HTTP에는 method, caching option, links parameter, contents type 등등 서버와 클라이언트간에 소통시 &#39;분기&#39; 조건 역할을 할 정보들을 담을 수 있으니, &#39;리소스 uri&#39;라는 명칭 하나로 온갖 동작을 다 설계할 수 있기 때문. 이는 다형성의 원리를 따라 설계의 복잡도를 줄인 아키텍쳐이다. 주소에 모든 정보가 다 포함되면 서버가 아 대충 이거 하겠구나? 라는 은닉성도 없을뿐더러, 너무 길어지고 알아보기 쉽지 않기때문에 나온 구조조</li>
</ul>
<h4 id="rest-api-구성을-설명하라-가장-간단한-핵심-규칙만-풀어써보자-아는대로로">REST API 구성을 설명하라 가장 간단한 핵심 규칙만 풀어써보자 아는대로로</h4>
<ul>
<li>위에 앵간하면 설명했는데 더 말하자면 http method 방식을 잘 알고 적절하게 사용하자.</li>
</ul>
<h4 id="html이란">HTML이란?</h4>
<ul>
<li>HyperText Markup Language</li>
<li>시멘틱 구주로 화면의 요소 구별 세팅 담당</li>
</ul>
<h4 id="브라우저는-따라서-뭘-렌더링하는-엔진인가">브라우저는 따라서 뭘 렌더링하는 엔진인가?</h4>
<ul>
<li>화면을 구성하는 3개 파일을 렌더링 하지.</li>
</ul>
<h4 id="그럼-요청해서-나오는-응답의-결과가-html이라면-http에는-html-데이터가-포함되어-있을까">그럼 요청해서 나오는 응답의 결과가 HTML이라면 HTTP에는 HTML 데이터가 포함되어 있을까?</h4>
<ul>
<li>당빠 HTTP 바디 부분에 html이 담겨 나온다.</li>
</ul>
<h3 id="파이썬으로-json-데이터-다루기">파이썬으로 JSON 데이터 다루기</h3>
<h4 id="json이란-무슨-약자인가">JSON이란? 무슨 약자인가?</h4>
<ul>
<li>JavaScript Object Notation</li>
<li>자바스크립트 문법을 따르는 컨테이너 객체 형태인데, 이 문법 형식과 같은 방식으로 문자열을 입력하여 JSON 해석기로 필요한 데이터를 통신하는 방식으로 JSON이 활용되게 바뀜</li>
</ul>
<h4 id="json은-파이썬의-어떤-객체들이-합쳐진-모습과-유사하지">JSON은 파이썬의 어떤 객체들이 합쳐진 모습과 유사하지?</h4>
<ul>
<li>딕셔너리와 리스트가 합쳐진 상태이다.</li>
</ul>
<h4 id="문법으로-주의할-사항-항상-뭐로-요소를-감싸는가-왜-그럴까-좀만-더-생각해봐">문법으로 주의할 사항 항상 뭐로 요소를 감싸는가? 왜 그럴까? 좀만 더 생각해봐</h4>
<ul>
<li>&quot;&quot; 큰따옴표로 감싸줘야 한다. 왜그러냐? 어떤 언어에서든 통용하여 사용하기에 요소 구분을 &quot;&quot;로 파싱하여 해석하기 때문이다.</li>
</ul>
<h4 id="파이썬을-웹이-이해하는-형태로-바꿀려면-무슨함수-걔가-뭘-반환하길래">파이썬을 웹이 이해하는 형태로 바꿀려면? 무슨함수? 걔가 뭘 반환하길래?</h4>
<pre><code class="language-py">  import json
  jsonStr = json.dumps(dic, ensure_ascii=False)</code></pre>
<ul>
<li>JSon 형식을 따르는 문자열 형태로 바꾼다.</li>
</ul>
<h4 id="그-함수에서-한글이-포함되어-있다면-왜-그렇게-매개변수를-넘기지">그 함수에서 한글이 포함되어 있다면? 왜? 그렇게 매개변수를 넘기지?</h4>
<ul>
<li>ensure_ascii=False</li>
<li>아스키가 영어를 전달하기에 효율적이기 때문에 일반적으로 ascii로 전달하고 해석하려한다. 유니코드 형태로 전달하려면 ensure_ascii 옵션을 false로</li>
</ul>
<h4 id="자-웹에서-온걸-파이썬이-이해하기-쉽게-하려면-뭘해야될까-그걸-해주는-함수는">자 웹에서 온걸 파이썬이 이해하기 쉽게 하려면? 뭘해야될까? 그걸 해주는 함수는?</h4>
<pre><code class="language-py">import json
dic = json.loads(jsonStr)</code></pre>
<h4 id="프로그램밍언어가-프로그래밍-언어가-아닌-다른-녀석이-이해할-수-있는-포맷으로-바꿔주는걸-뭐라고-하고-그-반대는-뭘까">프로그램밍언어가 프로그래밍 언어가 아닌 다른 녀석이 이해할 수 있는 포맷으로 바꿔주는걸 뭐라고 하고, 그 반대는 뭘까?</h4>
<ul>
<li>다른 녀석이 이해 -&gt; 직렬화</li>
<li>다시 직렬화의 반대 -&gt; 역직렬화</li>
</ul>
<h4 id="역직렬화의-결과는">역직렬화의 결과는??</h4>
<ul>
<li>딕셔너리 혹은 딕셔너리 리스트</li>
</ul>
<h4 id="json-응답을-데이터프레임으로-바꾸면-장점-어떻게-바꾸나">JSON 응답을 데이터프레임으로 바꾸면 장점? 어떻게 바꾸나?</h4>
<ul>
<li>판다스 패키지의 데이터프레임은 행렬형태의 자료를 효과적으로 다루는 함수들이 다량 정의되어 있어서 장점이 크다</li>
</ul>
<pre><code class="language-py">import pandas as pd
# pd.read_json(jsonStr) 문법적으로 전혀 오류 없어보이지만 주의해야한다. 매개변수로 스트링이긴 한데 파일 경로 타입만 받는다.
from io import StringIO
pd.read_json(StringIO(jsonStr)) #jsonStr을 읽을 수 있는 파일패스로 변경해주는 함수로 감싸서 동작작</code></pre>
<h3 id="파이썬에서-xml-다루기">파이썬에서 XML 다루기</h3>
<h4 id="xml-무슨-약자-자-html과-비교하여-xml이-좀-더-우위에-있는게-어떤게-우위에-있을까">XML 무슨 약자? 자 HTML과 비교하여 XML이 좀 더 우위에 있는게 어떤게 우위에 있을까?</h4>
<ul>
<li>eXtensible Markup Language</li>
<li>HTML은 브라우저가 이해하는 문법이지 사람이 이해하기엔 벅차다.</li>
<li>기계도 이해하고 사람도 이해하면서 단순히 데이터 깊이를 나눠서 전달할 수 있는 문법이 있다면? -&gt; 그게 XML</li>
<li>HTML처럼 태그 문법으로 구조를 나눈다.</li>
</ul>
<h4 id="문법적-요소를-설명하라-뭐로-감싸지고-그-대상은-뭔지만">문법적 요소를 설명하라. 뭐로 감싸지고 그 대상은 뭔지만?</h4>
<ul>
<li>모든 태그는 엘리먼트 요소임을 표현한다. 엘리먼트는 내부적으로 값을 가진다.</li>
<li>엘리먼트가 엘리먼트를 값으로 가질 수도 있고 엘리먼트 여러개를 값으로 가질 수도 있다. 다만 XML은 반드시 시작노드에는 시작 엘리먼트 하나만 존재할 수 있다. </li>
<li>즉 같은 레벨의 태그를 연달아 올리수 없고 같은 레벨의 태그를 연달아 나열하려면 반드시 상위 태그의 엘리먼트로 감싼다. 즉 트리 구조를 무조건 따라야 한다는 강제성이 존재재</li>
</ul>
<h4 id="역직렬화한-결과는-그리고-그-새끼를-다루는-가장-기본적인거-만약-부모-엘리-자식엘리가-존재할때-자식엘리-접근은-아주-ㅈ같네-이거-왜-그렇게-위험한-방법은-왜-위험한건가">역직렬화한 결과는? 그리고 그 새끼를 다루는 가장 기본적인거? 만약 부모 엘리 자식엘리가 존재할때 자식엘리 접근은? 아주 ㅈ같네 이거? 왜 그렇게? 위험한 방법은 왜 위험한건가?</h4>
<ul>
<li>역직렬화한 결과는 딕셔너리 리스트가 되었으면 참 좋겠는다 그 새끼는 그게 아니다. XML파서가 전문적으로 존재하면 래퍼 클래스이다. 데이터 프레임 같은건데 아주 ㅈ같다.<pre><code class="language-py">import xml.etree.ElementTree as et
book = et.fromstring(xmlStr)
# et.Element 객체가 된다. 내부적으로 tag필드로 tag 값을 가지고 있고 text필드로 요소값이 저장되어 있다.</code></pre>
</li>
</ul>
<h4 id="직렬화-역직렬화-아주-개-ㅈ같은거의-핵심은-json과-달리-반드시-강제되는-문법적-요소가-있네-보니까">직렬화 역직렬화 아주 개 ㅈ같은거의 핵심은? JSON과 달리 반드시 강제되는 문법적 요소가 있네 보니까</h4>
<ul>
<li>위에 언급했다. HTML마냥 저주받았다.</li>
</ul>
<h4 id="여러개의-키값을-확인하는-findall-문법-사용시-중의할점-그-원리-설명-왜-개-ㅈ같은지-시발-욕밖에-안나오네-이딴걸-왜씀-뭐-강점이-아예-없진-않지">여러개의 키값을 확인하는 findall() 문법 사용시 중의할점. 그 원리 설명. 왜 개 ㅈ같은지 시발 욕밖에 안나오네. 이딴걸 왜씀? 뭐 강점이 아예 없진 않지</h4>
<pre><code class="language-py"># 자 xmlStr이 &quot;&lt;book&gt;혼공분석&lt;/book&gt;&quot; 이러면 너무나도 해피하지. 
import xml.etree.ElementTree as et
book = et.fromString(xmlStr)
print(book.tag) #book
print(book.text) #혼공분석

#만약 태그 내에 여러 태그가 존재하는 상황? &quot;&lt;book&gt;&lt;e&gt;혼공분석&lt;/e&gt;&lt;e&gt;혼공만파파&lt;/e&gt;&lt;e&gt;혼공러닝닝&lt;/e&gt;&lt;/book&gt;&quot;
book2 = et.fromString(xmlStr) #여전히 Element객체 안에 뭐가 들었는지 이것만으로 알기 어려워서 ㅈ같은거
print(book.tag) #book
print(book2.text)  # 출력: None ㅈ같다.
# 자식 엘리먼트들의 내용을 출력하기 위해 반복문을 사용한다.
for child in book2:
    print(&quot;Child tag:&quot;, child.tag, &quot;, text:&quot;, child.text)
# =&gt; 이렇게 하면 각 &lt;e&gt; 태그의 내용을 확인할 수 있다.


# 예제 XML 데이터: &lt;books&gt; 안에 여러 &lt;book&gt; 요소가 존재하며,
# 각 &lt;book&gt; 내부에 책 제목, 저자, 출간일을 나타내는 태그들이 있습니다.
xmlStr = &quot;&quot;&quot;
&lt;books&gt;
   &lt;book&gt;
      &lt;name&gt;혼공분석&lt;/name&gt;
      &lt;author&gt;홍길동&lt;/author&gt;
      &lt;date&gt;2025-05-29&lt;/date&gt;
   &lt;/book&gt;
   &lt;book&gt;
      &lt;name&gt;혼공알고&lt;/name&gt;
      &lt;author&gt;임꺽정&lt;/author&gt;
      &lt;date&gt;2025-05-28&lt;/date&gt;
   &lt;/book&gt;
   &lt;book&gt;
      &lt;name&gt;혼공만파&lt;/name&gt;
      &lt;author&gt;유관순&lt;/author&gt;
      &lt;date&gt;2025-05-27&lt;/date&gt;
   &lt;/book&gt;
&lt;/books&gt;
&quot;&quot;&quot;

# XML 문자열을 파싱하여 최상위 요소(여기서는 &lt;books&gt; 객체)를 얻습니다.
root = et.fromstring(xmlStr)
print(&quot;최상위 태그:&quot;, root.tag)  # 결과: books

# findall()을 이용해 &lt;books&gt; 요소 내의 모든 &lt;book&gt; 자식 요소들을 찾습니다.
for book in root.findall(&#39;book&#39;):
    # findtext()는 자식 요소의 텍스트 값을 바로 반환합니다.
    name = book.findtext(&#39;name&#39;)
    author = book.findtext(&#39;author&#39;)
    date = book.findtext(&#39;date&#39;)

    print(&quot;-----------&quot;)
    print(&quot;책 제목:&quot;, name)   # 예: 혼공분석 등
    print(&quot;저자:&quot;, author)    # 예: 홍길동 등
    print(&quot;출간일:&quot;, date)    # 결과: 2025-05-29 등</code></pre>
<h3 id="api로-20대가-가장-좋아하는-도서-찾기">API로 20대가 가장 좋아하는 도서 찾기</h3>
<h4 id="가장-먼저-해야할-것">가장 먼저 해야할 것</h4>
<ul>
<li>api, 데이터셋 찾아보기기</li>
</ul>
<h4 id="api를-호출하는-url-작성하기-호출url과-파라미터로-구분하여-분석-도서관-정보나루-공개-api-사용하는-코드를-분석-ㄱㄱㄱ">API를 호출하는 URL 작성하기. 호출URL과 파라미터로 구분하여 분석 도서관 정보나루 공개 API 사용하는 코드를 분석 ㄱㄱㄱ</h4>
<ul>
<li>api문서를 보면서 각 파라미터 한번 읽어보고 -&gt; 분석하여 -&gt; 필요한 데이터만 사용하기 -&gt; 쓰잘데기 없는거 넣어봤자 길이만 냅다 늘어남.</li>
<li>만약 api 업데이트로 파라미터가 달라지면? -&gt; 그럴수 있다. 다만 호출용 파라미터가 자주 일어나면 아주 ㅈ같은 api. 원래 api URL은 자주 바뀌면 안된다.</li>
</ul>
<h4 id="바로-손코딩-api-호출-ㄱㄱ">바로 손코딩 api 호출 ㄱㄱ</h4>
<pre><code class="language-py"># 리퀘스트 요청 바로 때릴 수 있는 모듈
import requests

# 키 변수, url 변수 나누고 key를 URL 변수에 담아서 저장해보기
key = &quot;4e39afc515253ef8c660ac7c5cb3e221590398f21d9d911ce5505ae5907ba2da&quot;

url = f&quot;http://data4library.kr/api/loanItemSrch?format=json&amp;startDt=2021-04-01&amp;endDt=2021-04-30&amp;age=20&amp;authKey={key}&quot;


# get 방식으로 url 날려서 응답 저장
response = requests.get(url.format(isbn))

# 응답을 역직렬화
data = response.json()

#복잡한 리스폰스 객체를 확인한뒤에 어떤 방식으로 for문을 돌려야 책 제목을 리스트에 담을 수 있을까?
print(data)
</code></pre>
<h3 id="공개-api로-웹에서-데이터-가져오기-문제">공개 API로 웹에서 데이터 가져오기 &lt;문제&gt;</h3>
<h4 id="문제-해결과정을-말로-풀어-설명하면-끝">문제 해결과정을 말로 풀어 설명하면 끝</h4>
<ol>
<li>필요한 데이터가 있다. -&gt; 서치 -&gt; api찾기</li>
<li>api 사용방법을 읽어보기 혹은 print찍어보기 -&gt; 분석 -&gt; 어떤 데이터를 사용할지 감잡기</li>
<li>dataframe을 만들어서 정형화하기 -&gt; csv파일로 저장하기 -&gt; 분석결과 공유</li>
</ol>
<h3 id="확인-문제">확인 문제</h3>
<ol>
<li>2</li>
<li>1</li>
<li>2</li>
<li>json string</li>
<li>3</li>
<li>1</li>
</ol>
<h2 id="02-2-웹-스크래핑">02-2 웹 스크래핑</h2>
<h3 id="도서-쪽수를-찾아서-시나리오">도서 쪽수를 찾아서 (시나리오)</h3>
<h4 id="api에서-제공하지-않는-도서-쪽수를-가져와서-만들고-싶다면-어떻게-해야될까-시작과정만">API에서 제공하지 않는 도서 쪽수를 가져와서 만들고 싶다면 어떻게 해야될까? 시작과정만</h4>
<ul>
<li>도서 쪽수가 나와있는 사이트에서 스크래핑. 해당 도서 페이지에 접근하기 위한 파라미터가 뭔지 파악후 접근. 스크래핑을 위해선 requests beautifulsoup 이라는 라이브러리 사용할 것것</li>
</ul>
<h4 id="yes24-사이트의-파라미터가-당황스럽다-저런-숫자-데이터는-무엇인지-분석-httpswwwyes24comproductgoods116253011-뒤에-있는-숫자는-isbn이-아니다">yes24 사이트의 파라미터가 당황스럽다. 저런 숫자 데이터는 무엇인지 분석 <a href="https://www.yes24.com/product/goods/116253011">https://www.yes24.com/product/goods/116253011</a> 뒤에 있는 숫자는 ISBN이 아니다.</h4>
<ul>
<li>검색창에 &#39;혼공분석&#39; 이라고 치니까 <a href="https://www.yes24.com/product/search?domain=ALL&amp;query=%25ED%2598%25BC%25EA%25B3%25B5%25EB%25B6%2584%25EC%2584%259D">https://www.yes24.com/product/search?domain=ALL&amp;query=%25ED%2598%25BC%25EA%25B3%25B5%25EB%25B6%2584%25EC%2584%259D</a> 이런식으로 나왔다.</li>
<li>국내도서 카테고리로 한정을 하니 <a href="https://www.yes24.com/product/search?domain=BOOK&amp;query=%25ED%2598%25BC%25EA%25B3%25B5%25EB%25B6%2584%25EC%2584%259D&amp;page=1&amp;size=24">https://www.yes24.com/product/search?domain=BOOK&amp;query=%25ED%2598%25BC%25EA%25B3%25B5%25EB%25B6%2584%25EC%2584%259D&amp;page=1&amp;size=24</a> </li>
<li>(추리 이후)isbn으로 검색해보니 <a href="https://www.yes24.com/product/search?domain=BOOK&amp;query=9791169210287">https://www.yes24.com/product/search?domain=BOOK&amp;query=9791169210287</a></li>
<li>하지만 도서 상세 페이지로 들어가니 주소는 <a href="https://www.yes24.com/product/goods/116253011">https://www.yes24.com/product/goods/116253011</a></li>
<li>따라서 실제 도서 페이지의 숫자는 isbn이 아닌 yes24 데이터베이스 고유키이고, isbn 검색을 통해 나온 첫번째 도서로 직접 들어가는 2번 리퀘스트 요청을해야 쪽수에 접근 가능할 것이라는 결론론</li>
</ul>
<h4 id="결과적으로-그러면-저-숫자를-이용한-url을-만들어서-호출해야되는데-그-과정을-논리적으로-순서화해봐라-isbn을-어떻게-활용할수-있을지-검색창에-isbn을-입력한-결과-url은-httpswwwyes24comproductsearchdomainallquery9791162243664">결과적으로 그러면 저 숫자를 이용한 URL을 만들어서 호출해야되는데 그 과정을 논리적으로 순서화해봐라 ISBN을 어떻게 활용할수 있을지 검색창에 ISBN을 입력한 결과 URL은 <a href="https://www.yes24.com/product/search?domain=ALL&amp;query=9791162243664">https://www.yes24.com/product/search?domain=ALL&amp;query=9791162243664</a></h4>
<ul>
<li>위에 다 적은듯듯</li>
</ul>
<h3 id="검색-결과-페이지-가져오기코드">검색 결과 페이지 가져오기(코드)</h3>
<pre><code class="language-py">#### 가장 먼저 할일? -&gt; 20대가 가장 좋아하는 도서 목록을 만들기 위한 데이터 가져오기 gdown 코드 검색
gdownFilePath = &#39;https://bit.ly/3q9SZix&#39;
gdownOutputFilePath =  &#39;./20s_best_books.json&#39;

# !pip install gdown
# import gdown
# gdown.download(gdownFilePath, gdownOutputFilePath)

#### 우리가 원하는거 뭐? &quot;쪽수&quot; 그러기 위해 필요한게 뭐? &quot;검색어&quot; &quot;ISBN&quot; 혹은 그외 도움되는 데이터를 담은 데이터프레임으로 전처리 ㄱㄱ
# !pip install pandas
import pandas as pd
bookDF = pd.read_json(&#39;20s_best_books.json&#39;) # 여기까지가 전체 데이터를 담음 데이터 프레임
bookDF.head(20) #무슨 칼럼만 필요할지 일단 호출로 확인인


#### 데이터프레임이 있을때 행인덱스(숫자겠지) 열인덱스(숫자도 가능하지만 속성키워드도 있지)를 이용하여 원하는 방식으로 dataframe을 짜는 함수, 그리고 유용한 슬라이싱 개념
# 확인 결과 no ranking bookname authors publisher publication_year isbn13 까지 정도만 그 중 일부여도 상관은 없을 듯듯
bookDF1 = bookDF[[&#39;no&#39;, &#39;bookname&#39;, &#39;isbn13&#39;]] # 가장 일반적인 필요한 열만 찝어서 직접 만드는 방식
# bookDF1.head(20)
bookDF2 = bookDF.loc[[0,1],[&#39;no&#39;, &#39;bookname&#39;, &#39;isbn13&#39;]] #loc 사용법법
bookDF2 = bookDF.loc[0:20, &#39;no&#39;:&#39;isbn13&#39;] #loc 와 슬라이싱싱
# bookDF2.head(20)
bookDF3 = bookDF.iloc[0:20, [0,2,6]] # iloc와 슬라이싱
bookDF3.head(20)
# print(bookDF3.get(&#39;isbn13&#39;)[0])

#### 왜 loc는 함수면서 [] 대괄호를 사용하는거지? -&gt; 이유 설명 ㄱㄱ -&gt; 내부적으로 무엇이 돌고 있고, 어떤 작업을 해놨기에 이런게 가능한지 컨셉츄얼하게
# 모든 컨테이너 클래스는 []내부 요소 탐색 연산자를 지원하며 []연산자가 올때 호출되는 함수는 __getitem__ 이라고 정의된 함수이다. 이 함수에 [] 안에 들어가는 매개변수를 넣으면 적절하게 동작하도록 정의가 되어 있다. loc 클래스도 마찬가지로 내부적으로 getitem 함수가 정의되어 있기때문에 []로 동작하는 것것

#### 이제 ISBN을 알았으니 실제 호출해보기 yes24 호출해보기 -&gt; URL에 변수가 들어가야할 곳에 적절히 넣어 response로 HTML 받아오기 url=&quot;변수 받기위한 준비&quot; url.format(변수) 이런식으로 해보기
# yes24URL = &quot;https://www.yes24.com/product/search?domain=ALL&amp;query=9791169210287&quot;
# 우리가 빛의 속도로 갈 수 없다면 isbn 9791190090018
import requests
url = &quot;https://www.yes24.com/product/search?domain=BOOK&amp;query={}&quot; #빈칸 url
isbn = bookDF3.get(&#39;isbn13&#39;)[0]
res = requests.get(url=url.format(isbn))
print(res.text)</code></pre>
<h3 id="html에서-데이터-추출하기--뷰티풀수프--html파서">HTML에서 데이터 추출하기 : 뷰티풀수프 : HTML파서</h3>
<h4 id="뷰티풀수프-뭔지-간단-요약목적위주-requests와-뷰티풀-수프를-합친-패키지가-있다-그게-뭔지-이름만">뷰티풀수프 뭔지 간단 요약(목적위주), requests와 뷰티풀 수프를 합친 패키지가 있다 그게 뭔지 이름만</h4>
<ul>
<li>뷰티풀수프는 html 요소를 파싱하여 정보를 가져오는데 특화된 함수들이 정의된 라이브러리 패키지이다. scrapy 스크라피라는 패키지가 있음.</li>
</ul>
<h4 id="뷰티풀수프를-사용하기-전에-뭐부터-할까-그니까-html을-받아온것까지-했다면-뭘해야할까-분석한-결과까지-써보기기">뷰티풀수프를 사용하기 전에 뭐부터 할까? 그니까 HTML을 받아온것까지 했다면 뭘해야할까? 분석한 결과까지 써보기기</h4>
<ul>
<li>실제 우리가 원하는 링크값이나 텍스트값이 어느 요소에 있는지를 파악해야한다. </li>
<li>첫째 검색결과 페이지에서 링크값을 가져온다.</li>
<li>둘째 링크값으로 들어간 상세페이지에서 쪽수 값을 가져온다.</li>
</ul>
<h4 id="실습">실습</h4>
<pre><code class="language-py">#### beautiful soup 을 사용하기 위한 모든 코드들 -&gt; 라이브러리 -&gt; HTML이라고 해석할 수 있는 상태만들기
# !pip install bs4
from bs4 import BeautifulSoup
#a 태그 class=&#39;gd_name&#39; 의 href값이 필요한 값이다.
bs = BeautifulSoup(res.text, &#39;html.parser&#39;) #뷰티풀숩 객체 생성
aElement = bs.find(name=&#39;a&#39;, attrs={&#39;class&#39;:&quot;gd_name&quot;}) # a 태그 중 속성으로ㅗ class gd_name 가져오기기
# print(aElement)
print(aElement.attrs.get(&#39;href&#39;)) #isbn이 아닌 진짜 상세 페이지로 접근 가능한 키 url

#### 이제 어디로 가야될지 알았으니 가서 진짜 HTML 가져오기 -&gt; 어느 블럭으로 가야 쪽수를 가져올수 있을까?
import requests
url1 = &quot;https://www.yes24.com/product/search?domain=BOOK&amp;query={}&quot; #빈칸 url
isbn = bookDF3.get(&#39;isbn13&#39;)[0] #첫번째 도서의 isbn값값
res = requests.get(url=url.format(isbn))

bs1 = BeautifulSoup(res.text, &#39;html.parser&#39;) #뷰티풀숩 객체 생성
aElement1 = bs.find(name=&#39;a&#39;, attrs={&#39;class&#39;:&quot;gd_name&quot;}) # a 태그 중 속성으로ㅗ class gd_name 가져오기기
pkey = aElement.attrs.get(&#39;href&#39;)
url2 = &quot;https://www.yes24.com/{}&quot;
res2 = requests.get(url=url2.format(pkey))#진짜 상세 페이지 이동

#테이블이 여러개 있을 수 있다. 그중 쪽수는 품목 정보에 있으니 일단 품목 정보 요소를 전부 가져오기
# &lt;div id=&quot;infoset_specific&quot; class=&quot;gd_infoSet infoSet_noLine&quot;&gt;
#                                                                             &lt;tr&gt;
#                                 &lt;th class=&quot;txt&quot; scope=&quot;row&quot;&gt;쪽수, 무게, 크기&lt;/th&gt;
#                                 &lt;td class=&quot;txt lastCol&quot;&gt;344쪽 | 496g | 130*198*30mm&lt;/td&gt;
#                             &lt;/tr&gt;
# &lt;/div&gt;
# id는 고유한 값. 따라서 infoset_specific은 유일. 거기 안에서 tr을 전부 찾고. tr.th 를 탐색해보다 쪽수, 무게, 크기인 녀석을 찾아서 그 tr의 tr.td의 344쪽을 가져온다.


#### 요소를 찾았다면 해당 요소를 어떻게 가져오나?
bs2 = BeautifulSoup(res2.text, &#39;html.parser&#39;)
aElement2 = bs2.find(name=&#39;div&#39;, attrs={&#39;id&#39;:&#39;infoset_specific&#39;}) #품목정보를 담은 테이블 전체
trList = aElement2.find_all(name=&#39;tr&#39;) #tr 요소로 리스트 만들기기

answer = &#39;&#39;
for tr in trList:
    # print(f&quot;0 {tr}&quot;)
    if tr.find(name=&#39;th&#39;).text == &#39;쪽수, 무게, 크기&#39;:
        # print(tr.find(name=&#39;td&#39;).text)
        # print(tr.find(name=&#39;td&#39;).text[:4])
        answer = tr.find(name=&#39;td&#39;).text.split()[0]
        break


#### 해당요소를 가져왔다면 거기서 특정 태그를 다 가져오고 싶다면?
# find_all(name = &#39;태그명&#39;)

#### 특정 태그들을 가져왔다면 태그안에서 특정 값으로 요소를 한정하고 그 요소를 기반으로 원하는 요소의 변하는 쪽수값 가져오기
# find() == &#39;원하는 값&#39;

</code></pre>
<h3 id="전체-도서의-쪽수-구하기">전체 도서의 쪽수 구하기</h3>
<h4 id="for문으로-데이터-프레임을-감싸는건-비효율적이다-그래서-데이터-프레임은-내부적으로-반복하여-꺼내올수-있게-함수를-만들어-놨다">for문으로 데이터 프레임을 감싸는건 비효율적이다. 그래서 데이터 프레임은 내부적으로 반복하여 꺼내올수 있게 함수를 만들어 놨다.</h4>
<pre><code class="language-py">#### 데이터 프레임의 반복문을 사용하기 위해선 적용할 함수객체화 해야한다. 그래서 위의 과정을 하나의 함수화로 바꾸기
# get_page_cnt(isbn) isbn을 넣어주면 쪽수값을 가져온다.
def get_page_cnt(isbn):
    url = &quot;https://www.yes24.com/product/search?domain=BOOK&amp;query={}&quot;
    res = requests.get(url=url.format(isbn))
    bs = BeautifulSoup(res.text, &#39;html.parser&#39;)
    a_element = bs.find(name=&#39;a&#39;, attrs={&#39;class&#39;:&#39;gd_name&#39;})
    p_key = a_element.attrs.get(&#39;href&#39;)
    if not p_key: # href 속성을 찾지 못했을 경우
        print(f&quot;[{isbn}] a 태그에서 &#39;href&#39; 속성을 찾을 수 없습니다.&quot;)
        return &#39;&#39;
    url2 = &quot;https://www.yes24.com/{}&quot;
    res2 = requests.get(url2.format(p_key))
    bs2 = BeautifulSoup(res2.text, &#39;html.parser&#39;)
    a_element2 = bs2.find(name=&#39;div&#39;, attrs={&#39;id&#39;:&#39;infoset_specific&#39;})
    tr_list = a_element2.find_all(name=&#39;tr&#39;)
    for tr in tr_list:
        if tr.find(name=&#39;th&#39;).text == &#39;쪽수, 무게, 크기&#39;:
            return tr.find(name=&#39;td&#39;).text.split()[0]
    return &#39;&#39;

#### n개 행 가져오기
def get_page_cnt2(row):
    isbn = row[&#39;isbn13&#39;]
    return get_page_cnt(isbn)

ser_page_cnt = bookDF3.apply(get_page_cnt2, axis=1)
print(ser_page_cnt)

#### apply()란 무엇이고 언제 어떻게 사용하나?
#데이터 프레임에 사용하며 행에 적용할지 열에 적용할지 선택하며 첫번째 매개변수인 함수명을 적용하는 함수 적용하여 만들어진 값으로 시리즈를 반환함.

#### 람다를 이용하여 함수 축약하기 왜 이지랄? 이렇게 하니까 다른 놈들이. 왜 그렇게 하는데? 함수를 일급객체로 사용하는 것의 장점이겠지지
# 함수명이니까 실제 함수 구현 없이 익명함수를 이용하여 만들 수 있다는 것.

#### 데이터 프레임과 시리즈형을 합치는 함수 사용하여 찹쳐버리기, left_index, right_index 설명하기
#merge 함수이다.

</code></pre>
<h3 id="웹-스크래핑-주의점">웹 스크래핑 주의점</h3>
<h4 id="robotstxt란">robots.txt란?</h4>
<ul>
<li>robots.txt에 명시된 내용은 스크래핑하면 안된다.</li>
</ul>
<h4 id="html-태그를-특정할-수-없다면-그-대안은">HTML 태그를 특정할 수 없다면? 그 대안은?</h4>
<ul>
<li>셀레니움을 이용하라는 것 같다.</li>
</ul>
<h4 id="여기까지-과정을-간략히-설명하라">여기까지 과정을 간략히 설명하라.</h4>
<ul>
<li>찾고자하는 페이지에 접근하기 위한 과정</li>
<li>찾고자하는 페이지 속에서 요소를 찾는 과정</li>
<li>그렇게 함수를 만들고 나면 원하는 데이터 프레임에 apply 함수의 매개변수로 추가</li>
</ul>
<h3 id="확인-문제-1">확인 문제</h3>
<ol>
<li>4</li>
<li>4</li>
<li>1</li>
<li>2</li>
<li>3</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[혼공분석] 1주차]]></title>
            <link>https://velog.io/@flower-in-eyes/%ED%98%BC%EA%B3%B5%EB%B6%84%EC%84%9D-1%EC%A3%BC%EC%B0%A8</link>
            <guid>https://velog.io/@flower-in-eyes/%ED%98%BC%EA%B3%B5%EB%B6%84%EC%84%9D-1%EC%A3%BC%EC%B0%A8</guid>
            <pubDate>Mon, 07 Jul 2025 00:37:19 GMT</pubDate>
            <description><![CDATA[<h1 id="ch01-데이터분석을-시작하며">CH01 데이터분석을 시작하며</h1>
<h2 id="01-1-데이터-분석이란">01-1 데이터 분석이란</h2>
<h3 id="데이터-분석과-데이터-과학-인공지능-각각의-의미를-간단히-왜-사람마다-다-다른지">데이터 분석과 데이터 과학 인공지능 각각의 의미를 간단히. 왜 사람마다 다 다른지</h3>
<ol>
<li>왜 사람마다 정의가 다르냐? 서로 교집합이 존재하며 교집합을 어디에 포함시키냐가 다르기 때문</li>
<li>일반적으로는 데이터 과학이 인공지능과 데이터 분석을 포함하는 관계가 일반적</li>
<li>데이터 분석은 데이터 수집, 전처리, 마이닝 등 데이터를 가공하는것에 중점을 둔다고 본다. </li>
<li>인공지능은 모델 설계, 마이닝한 맥락대로 모델이 학습을 제대로 하고 있는지에 대한 모든것을 처리하는것에 중점을 두고</li>
<li>데이터 과학은 그 모든 수단을 활용하여 결과를 만드는것에 중점을 둔다고 본다.</li>
</ol>
<h4 id="머신러닝-데이터-마이닝-통계학-의미-간단히">머신러닝, 데이터 마이닝, 통계학 의미 간단히</h4>
<ol>
<li>위에 인공지능이 머신러닝 설명을 포함하며, 간단하게 모델 학습을 의미</li>
<li>위에 데이터 분석이 데이터 마이닝의 설명을 포함, 간단하게 데이터 속에서 패턴과 공식을 찾아내는것</li>
<li>통계학은 원론과 실습 모두이며, 표준편차의 이론 같은 것을 활용한 도구 사용방식이라고 본다.</li>
</ol>
<h4 id="통계학으로-접근한-데이터-분석-기술통계-탐색적-데이터-분석-가설검정을-서로간의-구별되는-특징으로-요약">통계학으로 접근한 데이터 분석. 기술통계, 탐색적 데이터 분석, 가설검정을 서로간의 구별되는 특징으로 요약</h4>
<ul>
<li>다시</li>
</ul>
<ol>
<li>기술통계: 통계학을 도구적 관점으로 본계 기술통계</li>
<li>탐색적 데이터 분석: EDA </li>
<li>가설 검정:</li>
</ol>
<h4 id="넓은-의미수행업무적의-데이터-분석과-좁은-의미기술적의-데이터-분석으로-구분해봐라">넓은 의미(수행업무적)의 데이터 분석과 좁은 의미(기술적)의 데이터 분석으로 구분해봐라.</h4>
<ol>
<li>좁은 의미: 데이터 분석과정에서 알아야하는 기술적 요건들</li>
<li>넓은 의미: 데이터 분석과정에서 필요한 준비 및 아웃풋하는 것까지 전부포함</li>
</ol>
<h4 id="데이터-분석-도구-넘파이-판다스-맷플롯립-사이킷런-사이파이-도구들-구별되는-특징으로-요약">데이터 분석 도구, 넘파이, 판다스, 맷플롯립, 사이킷런, 사이파이 도구들 구별되는 특징으로 요약</h4>
<ol>
<li>넘파이: 다차원 배열자료구조를 제공하며 강력한 인터페이스도 제공</li>
<li>판다스: 데이터 프레임이 대표적인 자료구조이며, 행렬 데이터를 조작하는데 필요</li>
<li>맷플롯립: 시각화</li>
<li>사이킷런: 머신러닝 학습 라이브러리</li>
<li>사이파이: 과학 수학 공식들을 간단한 함수호출로 실행하게 만들어줌</li>
</ol>
<h3 id="데이터-마이닝과-머신러닝-차이점-구별">데이터 마이닝과 머신러닝 차이점 구별</h3>
<ol>
<li>데이터 마이닝은 패턴을 인간이 뽑아냄</li>
<li>머신러닝은 패턴을 기계가 학습함</li>
</ol>
<h3 id="머신러닝도-패턴-데이터-마이닝도-패턴-그런데-왜-데이터-마이닝이-필요하지">머신러닝도 패턴 데이터 마이닝도 패턴 그런데 왜 데이터 마이닝이 필요하지?</h3>
<ol>
<li>머신러닝이 학습하기 위한 패턴이란 공식은 인간이 제시를 해줘야함. 즉 광범위하고 핵심을 잘 잡은 데이터 마이닝이 성공적인 머신러닝의 필수 조건</li>
</ol>
<h3 id="확인문제">확인문제</h3>
<ol>
<li>2 : 소프트웨어 설계</li>
<li>4 : 웹앱 개발</li>
</ol>
<h2 id="01-2-구글-코랩과-주피터-노트북">01-2 구글 코랩과 주피터 노트북</h2>
<h3 id="확인-문제">확인 문제</h3>
<ol>
<li>2</li>
<li>3</li>
<li><ol>
<li>4</li>
<li>1</li>
<li>2</li>
<li>3</li>
</ol>
</li>
</ol>
<h2 id="01-3-이-도서가-얼마나-인기가-좋을까요">01-3 이 도서가 얼마나 인기가 좋을까요?</h2>
<p>학습 목적: 데이터 분석을 해가는 과정을 읽어보며 감잡기</p>
<h3 id="도서-데이터-찾기-데이터가-없는-경우-혹은-찾기어려운-경우는-비일비재-이럴때-제일-먼저-찾는-방법">도서 데이터 찾기: 데이터가 없는 경우 혹은 찾기어려운 경우는 비일비재. 이럴때 제일 먼저 찾는 방법?</h3>
<ol>
<li>오픈 데이터셋</li>
<li>오픈 api</li>
<li>유료 데이터 및 api</li>
<li>크롤링</li>
</ol>
<h3 id="코랩으로-데이터-로드하기">코랩으로 데이터 로드하기</h3>
<p>막힘</p>
<h4 id="csv를-선호하는-이유">CSV를 선호하는 이유?</h4>
<ul>
<li>가벼움. 텍스트와 컴마만으로 이루어져 있어 조작이 간편</li>
</ul>
<h4 id="gdown-패키지란">gdown 패키지란?</h4>
<ul>
<li>googledrive url을 이용하여 바로 원하는 경로에 다운로드 하는 패키지</li>
</ul>
<h3 id="파이썬으로-csv-다루기">파이썬으로 CSV 다루기</h3>
<pre><code class="language-python"># 로드
%pip install gdown

# import gdown
# bool isShow = False
# gdown.download(url=&quot;url&quot;,output=&quot;filepath&quot;, quiet=isShow)
import gdown

b_csv = gdown.download(&#39;https://bit.ly/3eecMKZ&#39;,
               &#39;남산도서관 장서 대출목록 (2021년 04월).csv&#39;, quiet=False)

# 프린트
for text in b_csv.readline():
  print(text)


# 파일 인코딩 체크: readmode 세팅, chardet.detect()
# 왜 확인하냐?
#    - CSV 인코딩이 UTF-8, CP949, EUC-KR 등 제각각이라 한글 깨짐 방지하려고. 
import chardet

with open(&#39;남산도서관 장서 대출목록 (2021년 04월).csv&#39;, &#39;rb&#39;) as f:
    raw = f.read(10000)  # 앞부분만 읽어도 OK
result = chardet.detect(raw)
print(result)  # {&#39;encoding&#39;: &#39;CP949&#39;, &#39;confidence&#39;: 0.99}

# 인코딩 형식 정하여 다시 로드
import pandas as pd

enc = result[&#39;encoding&#39;] or &#39;utf-8&#39;
df = pd.read_csv(
    &#39;남산도서관 장서 대출목록 (2021년 04월).csv&#39;,
    encoding=enc,
    low_memory=False  # dtype 경고 없애려고
)
print(df.head())

df = pd.read_csv(
    &#39;남산도서관 장서 대출목록 (2021년 04월).csv&#39;,
    encoding=enc,
    errors=&#39;replace&#39;,  # � 로 깨진 글자 대체
    low_memory=False
)</code></pre>
<h3 id="데이터프레임으로-다루기-판다스-판다스란-데이터-프레임이란-시리즈란-간단히">데이터프레임으로 다루기 판다스: 판다스란? 데이터 프레임이란? 시리즈란? 간단히</h3>
<pre><code class="language-python"># 판다스(Pandas): 파이썬에서 표 형태(테이블) 데이터를 다루기 위한 라이브러리  
# 데이터 프레임(DataFrame): 2차원 행·열 구조, SQL 테이블이나 엑셀 시트와 유사  
# 시리즈(Series): 1차원 배열, 데이터 프레임의 한 열(column)에 해당  

### 판다스로 csv 다루기

# 로드
import pandas as pd
df = pd.read_csv(
    &#39;남산도서관 장서 대출목록 (2021년 04월).csv&#39;,
    encoding=enc,         # 앞에서 감지한 인코딩
    low_memory=False      # 청크별 타입 추론 비활성화
)
print(df.shape, df.columns)

# low 메모리 에러는 왜 나오나? 해결법
# 파일이 크고 칼럼마다 데이터 타입이 섞여 있으면, pandas가 작은 청크 단위로 읽으며 dtype 경고 발생
# 해결: low_memory=False 로 한 번에 읽어서 일관된 타입 추론

# 다시 csv로 저장 to_csv
df.to_csv(
    &#39;processed_data.csv&#39;,
    index=False,           # 인덱스 열 제거
    encoding=&#39;utf-8-sig&#39;   # Excel 호환용 BOM 포함
)

# dataframe은 생성시 기본값이 자동으로 맨 왼쪽에 인덱스 열을 추가하는 것. 만약 끄고 싶다면? -&gt; index_col=0
df = pd.read_csv(&#39;file.csv&#39;, index_col=0)
df.to_csv(&#39;file.csv&#39;, index=False)

# 엑셀로 저장 -&gt; 필요한 라이브러리들 사용법
%pip install openpyxl
df.to_excel(
    &#39;output.xlsx&#39;,
    index=False,
    engine=&#39;openpyxl&#39;
)</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[방송대_논리회로_2강]]></title>
            <link>https://velog.io/@flower-in-eyes/%EB%B0%A9%EC%86%A1%EB%8C%80%EB%85%BC%EB%A6%AC%ED%9A%8C%EB%A1%9C2%EA%B0%95</link>
            <guid>https://velog.io/@flower-in-eyes/%EB%B0%A9%EC%86%A1%EB%8C%80%EB%85%BC%EB%A6%AC%ED%9A%8C%EB%A1%9C2%EA%B0%95</guid>
            <pubDate>Sat, 22 Mar 2025 02:23:50 GMT</pubDate>
            <description><![CDATA[<h2 id="01-논리-연산brbr">01 논리 연산<br><br></h2>
<h3 id="31-논리-연산brbr">3.1 논리 연산<br><br></h3>
<ul>
<li>현실 세계의 데이터를 표현 하는 방법에 여러가지가 있음 대표적인건 그래프나 표형태</li>
<li>2진 디지털 시스템에서 입출력 관계를 표현 하는 방법이 그래프와 진리표</li>
</ul>
<table>
<thead>
<tr>
<th>입력</th>
<th>출력</th>
</tr>
</thead>
<tbody><tr>
<td>X</td>
<td>F</td>
</tr>
<tr>
<td>0</td>
<td>1</td>
</tr>
<tr>
<td>1</td>
<td>0</td>
</tr>
<tr>
<td></td>
<td></td>
</tr>
<tr>
<td>진리 표의 예시<br><br></td>
<td></td>
</tr>
</tbody></table>
<ul>
<li><p>논리 함수</p>
</li>
<li><p>입력에 따라 출력이 어떻게 변하는가를 나타내는 함수로서도 표현할 수 있음</p>
</li>
<li><p>$f = \overline{x}$<br><br></p>
</li>
<li><p>논리연산(부울 연산)</p>
</li>
<li><p>참과 거짓을 처리하는 연산 0또는 1이 적용됨.(시스템에따라 0이 참일수도 있긴함. 일반적으로 0이 거짓)</p>
</li>
<li></li>
<li><p>논리 집합(부울 집합)</p>
</li>
<li><p>0 과 1로만 구성된 집합</p>
</li>
<li></li>
<li><p>논리 집합 + 논리 연산</p>
</li>
<li><p>0과 1을 입력 받아 규칙에 따라 특정 값을 출력함. </p>
</li>
<li></li>
<li><p>논리 회로란, 입력 신호의 논리 연산을 통해 출력 신호를 생성하는 회로. 회로의 형태로서 논리 연산을 수행할 수 있게 되어있음</p>
</li>
<li></li>
</ul>
<h4 id="312-논리-게이트brbr">3.1.2 논리 게이트<br><br></h4>
<h5 id="and-게이트---논리곱conjunctionbrbr">AND 게이트 - 논리곱(Conjunction)<br><br></h5>
<ul>
<li>모든 입력이 1이어야만 1을 출력</li>
<li>D모양으로 표현</li>
<li>F = XY<br><br></li>
</ul>
<h5 id="or-게이트---논리합disjunctionbrbr">OR 게이트 - 논리합(Disjunction)<br><br></h5>
<ul>
<li>입력 중 하나라도 1이면 1출력</li>
<li>얄쌍 D</li>
<li>f= x+ y<br><br></li>
</ul>
<h5 id="not-게이트---부정negationbrbr">NOT 게이트 - 부정(Negation)<br><br></h5>
<ul>
<li>입력을 그냥 반전 시킴</li>
<li>세모에 동그라미</li>
<li>$f = \overline{x}$<br><br></li>
</ul>
<h5 id="nor-게이트---not-orbrbr">NOR 게이트 - NOT OR<br><br></h5>
<ul>
<li>or 게이트의 결과를 반전 -&gt; 1이 하나라도 있으면 전부 0</li>
<li>or게이트 출력쪽에 동그라미<br><br></li>
</ul>
<h5 id="nand-게이트---not-andbrbr">NAND 게이트 - NOT AND<br><br></h5>
<ul>
<li>and 게이트의 결과를 부정하여 출력 -&gt; 모든 입력이 1이어야만 0</li>
<li>D출력쪽에 동그라미<br><br></li>
</ul>
<h5 id="xor-게이트---베타적-논리합brbr">XOR 게이트 - 베타적 논리합<br><br></h5>
<ul>
<li>입력이 서로 다를때만 1을 출력 -&gt; 하나라도 다르면 1</li>
<li>or 입력쪽에 선이 하나 더 있음<br><br></li>
</ul>
<h5 id="xnor-게이트---베타적-xorbrbr">XNOR 게이트 - 베타적 XOR<br><br></h5>
<ul>
<li>xor의 결과를 반대로 -&gt; 완전히 일치하면 1<br><br></li>
</ul>
<h5 id="논리하과-배타적-논리합brbr">논리하과 배타적 논리합<br><br></h5>
<ul>
<li>or: 하나라도 참이라면 참</li>
<li>xor: 둘이 달라야만 참</li>
</ul>
<h2 id="32-부울-대수brbr">3.2 부울 대수<br><br></h2>
<h3 id="321-부울대수의-개요brbr">3.2.1 부울대수의 개요<br><br></h3>
<h4 id="부울대수boolean-algebrabrbr">부울대수(boolean algebra)<br><br></h4>
<p>수학의 한 분야. 참과 거짓에 대해 다루는 수학.<br><br></p>
<h4 id="부울함수boolean-functionbrbr">부울함수(boolean function)<br><br></h4>
<p>부울 대수를 기반으로하는 함수. 부울 연산을 하나 이상 사용하여 정의 할 수 있음. 결국 부울 함수를 구현하는게 논리 회로 구현이라고도 보기도함. 복합적인 개체<br><br></p>
<h4 id="부울함수에-따른-논리회로의-작동-흐름brbr">부울함수에 따른 논리회로의 작동 흐름<br><br></h4>
<p>연산자 우선순위</p>
<ol>
<li>괄호</li>
<li>not</li>
<li>and, nand</li>
<li>or, nor</li>
<li>xor, xnor<br><br></li>
</ol>
<h4 id="부울함수와-진리표와의-관계brbr">부울함수와 진리표와의 관계<br><br></h4>
<ol>
<li>어떤 부울함수든 항상 진리표는 하나 -&gt; 정의역 요소에 대응되는 값은 하나라는 함수의 정의</li>
<li>하나의 진리표를 똑같이 공유하는 여러 부울함수 존재 -&gt; 이것 또한 함수의 정의</li>
<li>무조건 같은 진리표를 출력할수록(입력의 갯수가 같다면) 더 좋은 최적화된 논리 회로다.<br><br></li>
</ol>
<h4 id="부울함수의-간소화brbr">부울함수의 간소화<br><br></h4>
<ol>
<li>대수적인 방법 -&gt; 근본, 기반</li>
<li>도표를 이용한 방법 -&gt; 도구</li>
<li>테이블을 이용한 방법 -&gt; 도구<br><br></li>
</ol>
<h3 id="322-간소화-기본-공식brbr">3.2.2 간소화 기본 공식<br><br></h3>
<h4 id="부울대수의-쌍대성-원리principle-of-dualitybrbr">부울대수의 쌍대성 원리(principle of duality)<br><br></h4>
<ol>
<li>항 결합</li>
<li>문자 소거<br><br></li>
</ol>
<h3 id="324-부울함수의-보수brbr">3.2.4 부울함수의 보수<br><br></h3>
<p>드모르간의 법칙 활용<br><br></p>
<p>자세한 내용은 뒤에 더 나온다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[SICP_CH1_1_프로그래밍 기본 요소]]></title>
            <link>https://velog.io/@flower-in-eyes/SICPCH11%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EA%B8%B0%EB%B3%B8-%EC%9A%94%EC%86%8C</link>
            <guid>https://velog.io/@flower-in-eyes/SICPCH11%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EA%B8%B0%EB%B3%B8-%EC%9A%94%EC%86%8C</guid>
            <pubDate>Tue, 18 Mar 2025 06:43:03 GMT</pubDate>
            <description><![CDATA[<h2 id="추상화brbr">추상화<br><br></h2>
<ul>
<li><strong>관념 (idea)</strong> → 우리가 마음속에서 떠올리는 생각이나 개념</li>
<li><strong>단순 관념 (simple idea)</strong> → 더 이상 쪼갤 수 없는 가장 기본적인 개념<ul>
<li>예시: ‘빨강’(색깔 개념), ‘둥글다’(형태 개념), ‘차갑다’(온도 개념)</li>
</ul>
</li>
<li><strong>복합 관념 (compound idea)</strong> → 여러 개의 단순 관념을 합쳐서 만든 개념<ul>
<li>예시: ‘사과’(빨강 + 둥글다 + 차갑다)</li>
</ul>
</li>
<li><strong>복잡한 관념 (complex idea)</strong> → 복합 관념과 같은 의미로 쓰임 (더 많은 개념이 합쳐진 것)</li>
<li><strong>관계 관념 (relation idea)</strong> → 둘 이상의 관념을 비교해서 만드는 개념<ul>
<li>예시: ‘더 크다’, ‘더 작다’, ‘옆에 있다’ 같은 개념</li>
</ul>
</li>
<li><strong>추상화 (abstraction)</strong> → 특정한 사례에서 <strong>공통적인 특징만 뽑아서 일반적인 개념을 만드는 과정</strong><ul>
<li>예시: ‘개의 관념’ → 여러 종류의 개(골든 리트리버, 푸들 등)에서 공통적인 특징(4발, 짖음)을 추출하여 만든 개념
<br><br></li>
</ul>
</li>
</ul>
<ol>
<li><strong>단순한 개념들을 조합하면 더 복잡한 개념(복합 관념)이 된다.</strong>  </li>
<li><strong>두 개념을 비교하면 관계에 대한 개념(관계 관념)이 생긴다.</strong>  </li>
<li><strong>불필요한 요소를 빼고 공통적인 특징만 남기면 더 일반적인 개념(추상화)이 된다.</strong><br><br></li>
</ol>
<h2 id="계산적-과정-computational-processbrbr">계산적 과정 computational process<br><br></h2>
<ul>
<li><p><strong>계산적 과정 (Computational Process)</strong><br><br></p>
<ul>
<li>컴퓨터에서 어떤 연산을 수행하는 과정</li>
<li>단순한 계산보다 더 넓은 개념 (예: 반복문, 조건문, 알고리즘 실행 등)</li>
<li>실제 세상에 존재하는 것이 아니라, <strong>컴퓨터 내부에서 실행되는 추상적인 개념</strong></li>
</ul>
</li>
<li><p><strong>과정 (Process)</strong><br><br></p>
<ul>
<li>어떤 일을 단계적으로 수행하는 것</li>
<li><strong>&quot;계산적 과정&quot;</strong>이란 결국 <strong>컴퓨터가 수행하는 일련의 계산 및 연산 과정</strong>을 의미함.<br><br></li>
</ul>
<p><strong>🔹 과정과 ‘점차 전개됨’</strong><br><br></p>
</li>
<li><p>컴퓨터에서 실행되는 과정(process)은 <strong>한 번에 끝나지 않고, 단계적으로 진행됨.</strong></p>
</li>
<li><p>즉, 프로그램이 실행되면서 여러 개의 연산이 차례대로 수행됨.<br><br></p>
</li>
<li><p><strong>알고리즘 (Algorithm)</strong><br><br></p>
<ul>
<li>문제를 해결하기 위한 명확한 절차나 규칙의 집합</li>
<li>컴퓨터는 이 알고리즘을 <strong>계산적 과정</strong>으로 실행함.</li>
<li>예: 두 숫자의 최대공약수를 구하는 방법</li>
</ul>
</li>
<li><p><strong>재귀적 과정 (Recursive Process)</strong><br><br></p>
<ul>
<li>어떤 함수나 과정이 자기 자신을 반복적으로 호출하는 것</li>
<li>예: 팩토리얼 계산 (<code>n! = n * (n-1)!</code>)</li>
</ul>
</li>
<li><p><strong>반복적 과정 (Iterative Process)</strong><br><br></p>
<ul>
<li>일정한 조건이 만족될 때까지 같은 연산을 계속 반복하는 것</li>
<li>예: <code>for</code> 루프, <code>while</code> 루프<br><br></li>
</ul>
</li>
<li><p><strong>데이터 (Data)</strong><br><br></p>
<ul>
<li>컴퓨터가 처리하는 정보 (숫자, 문자, 이미지 등)</li>
</ul>
</li>
<li><p><strong>프로그램 (Program)</strong><br><br></p>
<ul>
<li>컴퓨터가 실행할 수 있도록 작성된 명령어들의 집합</li>
<li>프로그램이 곧 <strong>계산적 과정(computational process)을 제어하는 도구</strong></li>
</ul>
</li>
<li><p><strong>&quot;프로그램 = 주문(Spell)&quot;?</strong><br><br></p>
<ul>
<li>프로그래머는 컴퓨터에 명령을 내리는 역할을 함</li>
<li><strong>프로그램을 작성하는 행위가 마치 &quot;마법 주문을 외우는 것&quot;과 같다</strong>는 비유<br><br></li>
</ul>
</li>
</ul>
<h2 id="자바스크립트brbr">자바스크립트<br><br></h2>
<p>주문을 외우기 위해선 언어가 필요하다.
그러한 언어로 자바스크립트를 채택함. LISP의 방언인 Scheme의 주요 아이디어와, 셀프의 핵심 기능들을 전부 물려받아 완성되었기 때문<br><br></p>
<p> 스킴: 어휘순 범위(lexically scoped), 일급함수(first-class function)<br><br></p>
<p>셀프: 프로토타입 기반 객체지향 언어<br><br></p>
<p>웹 페이지 개발자들은 자바스크립트 코드를 페이지내에 실어 넣고, 웹브라우저 개발자들은 자바스크립트 해석기(인터프리터 및 컴파일러)를 탑재하는 형태<br><br></p>
<h2 id="11-프로그래밍의-기본-요소brbr">1.1 프로그래밍의 기본 요소<br><br></h2>
<p>프로그래밍 언어는 컴퓨터가 수행할 일을 지시하는 수단이다. 그런데 이 지시를 표현할때 다음 규칙이 없다면 강력한 프로그래밍 언어라고 할 수 없다. <br><br></p>
<ol>
<li>원시 표현식 (primitive expression): 가장 단순한 개체를 나타내는 표현 ex) x, 1, 0b123</li>
<li>조합(combination) 수단: 단순한 요소들을 복합적으로 만드는 것 ex) int x = 10;</li>
<li>추상화(abstraction) 수단: 복잡적인 요소에 이름을 붙여 하나의 단위로 다루는 것 ex) add();<br><br></li>
</ol>
<p>단순비교: 함수는 데이터를 다루는 규칙. 데이터는 재료<br><br></p>
<p>고급비교: 함수나 데이터는 그리 크게 다르지 않다.<br><br></p>
<h3 id="111-표현식-expressionbrbr">1.1.1 표현식 expression<br><br></h3>
<p>표현식은 컴퓨터가 이해하는 어떤 식을 의미한다. 수학에서 말하는 단항식일 수도 다항식일 수도 있다. x일지 2x+3y일지 모르지만 하여간 이런 것들이 식이다.<br><br></p>
<p>이러한 expression에 semicolon(;) 을 붙이면 문장(statement)가 되고 비로소 해석기는 표현식의 결과에 응답하게 된다. 표현식은 문장의 재료라 할 수 있음<br><br></p>
<p>문장은 반드시 하나 이상의 primitive expression이 포함되어 있다. 
여러 표현식이 포함된 표현식을 특히 combination이라고 칭함.
일반적으로 가장 흔한 피연산자(operand) 연산자(operator) 피연산자(operand) 이런식의 피연산자 사이에 연산자가 오는 수식같은 형태를 중위 표기법(infix notation)이라고 함.<br><br></p>
<p>수식 안에 괄호로 수식의 결과를 피연산자로 만드는 방식을 중첩(nesting) 이라 하고 이는 프로그래밍 언어에서도 흔히 쓰인다. 인간이 알아보기 힘든걸 알아보기 쉽게 만들어주지만, 논리만 같다면, 프로그램은 괄호를 쓰든 안쓰든 같은 속도로 처리해버린다.<br><br></p>
<p>REPL(Read Evaluate Print Loop): 우선순위에 맞게 읽고 평가하여 결과를 내뱉는 행위를 빠른 속도로 반복한다고 하여 붙여진 행위의 명칭이다.<br><br></p>
<p>REPL은 특별한 호출 명령없이 즉각적으로 해석되는 동작이다.<br><br></p>
<h3 id="112-이름-붙이기와-환경brbr">1.1.2 이름 붙이기와 환경<br><br></h3>
<p>계산적 객체(computational object)에 이름(name)을 붙일 수 있는 것은 프로그램언어의 필수 기능이다.<br><br></p>
<p>실제로 어떠한 컨셉을 표현하는데 있어 엄청나게 복잡할 수 있는 데이터나 식을 간단한 이름하나만으로 연산에 참여 시킬 수 있어야. 더 추상화되고 복잡한 개념을 표현 할 수 있어진다.<br><br></p>
<blockquote>
<p>자바 스크립트는 모든 문장이 값이라는 관례를 따른다. 이 관례와 자바스크립트 프로그래머들이 효율성은 신경쓰지 않는다는 평판이 자바스크립트 프로그래머는 모든 것의 가치를 알지만 그 대가는 전혀 모른다는 문구로 이어진다.
위의 말이 이해가 안되었었는데 풍자적 표현이었다.</p>
</blockquote>
<p>자바 스크립트는 모든 문장이 값이라는 관례를 따른다. -&gt; 실제로 const size = 2; 라는 문장은 그냥 단순한 할당 문이 아니라 그 자체로 값을 반환한다. 이걸 보여주는 대표 사례는 다음과 같다.</p>
<pre><code>int a; //선언문
int b = (a = 5) * 2; //할당과 동시에 5를 반환하기 때문에 연산에 참여가 되는것</code></pre><p><br><br></p>
<p>모든 것의 가치를 알지만 -&gt; 자바스크립트는 모든 문장이 함수가 전부 value로 처리되기 때문<br><br></p>
<p>그 대가는 전혀 모른다 -&gt; 유연함과 함수형 프로그래밍 덕분에 발생하는 무수히 많은 바레이션이 다양한 스타일을 만들고, 다양한 스타일 때문에 협업에서의 cost 발생을 우려하는 표현<br><br></p>
<h4 id="환경environmentbrbr">환경(environment)<br><br></h4>
<p>이름과 값의 쌍을 만드는 것을 지원하기 위해서 컴파일러가 해석한 내용들이 결국 어딘가에 저장되어 있어야함. 그 공간을 환경이라고 표현함. 환경은 여러 곳이 존재 할수 있고, 하나의 연산에 다른 여러 환경을 참조하는 경우도 많다.<br><br></p>
<h3 id="113-연산자-조합의-평가brbr">1.1.3 연산자 조합의 평가<br><br></h3>
<p>연산자(Operator): 특별한 규칙 및 우선순위가 지정된 기호 및 키워드. 산술 연산, 논리 연산, 할당 연산, 선언 연산 등등 다양한 원시동작을 구현함.<br><br></p>
<p>조합(Combination): 연산자와 피연산자가 결합된 조합. 그리고 그 조합과 조합이 다시 연산자로 결합된 복합 조합 등 연산자와 피연산자가 뭉쳐진 형태를 조합이라 함.<br><br></p>
<p>평가(Evaluation): 컴파일러가 하는 행위인데, 결국 하는건 문장 내의 표현식을 value화 하는 걸 칭함.<br><br></p>
<p>연산자 조합 평가: <strong>연산자 조합을 평가하는 과정에는 순서(우선순위)가 존재</strong>함.
연산자 우선순위에 따라 <strong>평가 순서</strong>가 결정됨.
연산이 계층적으로 나뉘며, 이를 <strong>트리(Tree) 구조</strong>로 나타낼 수 있음.
<strong>낮은 계층의 연산(우선순위가 높은 연산)이 먼저 평가됨.</strong>
이러한 과정은 재귀적인 아이디어이다. 복잡한 산술연산을 처리하기 위해 산술연산을 반복 호출하되 연산 결과가 하나씩 벗겨져서 최종 연산까지 전달된다.<br><br></p>
<p>재귀적(Recursive): 자기 자신을 호출하는 방식으로 문제를 해결하는 방법. 큰 문제를 해결하기 위해 끝나는 조건이 존재하는 작은 문제를 해결하고 그 해결된 값을 가지고 다시 한단계 큰 문제를 해결하는 형태로 최종 문제해결까지 반복함.<br><br></p>
<p>트리(Tree): 재귀적인 데이터를 표현하기에 적합한 구조 형태. 노드와 간선으로 표현이되면 전부 트리인데, 복합 조합 산술연산의 경우 가장 최종에 해야될 연산을 루트 노드에 놓고, 그 아래가지에 바로 피연산자들을 놓는다. 피연산자가 또 조합이라면 역시나 그 노드에는 피연산자의 최종 연산을 노드에 놓는다. 이를 반복하다보면 가장 작은 브랜치 노드에는 숫자들이 깔리게 되는데 이 숫자들을 부모 노드와 결합한 결과를 부모노드와 교체하면서 재귀적으로 문제가 해결됨을 표현할 수 있게 되는 것.<br><br></p>
<p>트리 누산(tree accumulation): 위에 다 설명해버렸다. 위로 계산 결과를 보내면서 누산한다고 해서 트리 누산이라 표현한다.<br><br></p>
<p>원시 표현식 평가 규칙:</p>
<ol>
<li>수치의 값은 해당 숫자들이 나타내는 바로 그 값이다.</li>
<li>이름의 값은 <strong>현재</strong> 환경에서 그 이름에 연관된 객체이다.<br><br></li>
</ol>
<p>키워드(keyword): <strong>이름짓기</strong>로 사용될 수 없는 특별한 단어들이다. 컴파일러는 이 키워드들이 어떻게 배치되어 있냐에 따라서 각기 다른 동작을 구현하는 것<br><br></p>
<p>구문형(syntactic form): 각 키워드마다 반드시 따라야하는 규칙이 있고, 해당 규칙을 따른 형태가 구문형이다. 함수 선언형, 클래스 선언형, 변수할당형, 산술연산형 등등 여러 구문형이 있다.<br><br></p>
<p>구문론(syntax): 문법을 의미하는것, 문법이 올바른지 아닌지는 키워드의 시작과 구현 배치 등을 통해 컴파일러가 판단한다.<br><br></p>
<h3 id="114-복합-함수brbr">1.1.4 복합 함수<br><br></h3>
<p>앞서 단순한 수치계산을 위해서 원시 표현식들과 원시 연산자들을 이용하여 했던 수치 계산을 넘어 더욱 복잡한 연산자를 만드는 방법이 무엇이냐? 그게 함수이다.<br><br></p>
<p>프로그래밍 언어는 원시타입을 제공하고, 프로그래머는 필요한 함수를 원시타입을 이용해 만들어야한다<br><br></p>
<p>그게 추상화다. 중첩과 조합의 수단을 이용하여 추상화를 하는것<br><br></p>
<p>함수 선언: 변수 선언과 마찬가지로 추상화 기법이며, 이름을 붙이는거다. 변수 선언은 간단한 표현식에 이름을 매겼다면, 함수선언은 좀 더 복잡한 조합에 이름을 붙인다고 일단 이해.<br><br></p>
<p>function  <em>이름</em>(<em>매개변수들</em>) { return <em>표현식</em>;}<br><br></p>
<p>함수 적용의 순서</p>
<ol>
<li>함수 표현식과 인수 표현식을 각각을 전부 부분 평가. 일단 잘라 놓고 시작. 중첩되더라도 이는 마찬가지</li>
<li>평가 이후 각각의 값이 도출되면 함수 값(구현된 그 내용)을 안쪽에서부터 표현식 값에  하나씩 적용하여 적용 값을 토해낸다.<br><br></li>
</ol>
<h3 id="115-함수-적용의-치환-모형brbr">1.1.5 함수 적용의 치환 모형<br><br></h3>
<p>복합 함수의 적용을 표현하는 모형(Modeling)이다. 자세한 내용은 책에서. <br><br></p>
<p>핵심은 </p>
<ol>
<li>함수표현식을 만나면 1.1.4에서 보았듯 표현식을 인수와 함수로 분리하여 적용하기 시작한다는 것. </li>
<li>그렇게 단순 인수에 함수 표현식을 적용해보려했더니 반환 타입이 원시 연산자가 아닌 또 다른 정의된 함수라면? 다시 1번을 반복한다는 것. 그렇게 최종 값이 만들어지면 그게 연산의 결과라는 것.<br><br></li>
</ol>
<h4 id="인수-우선-평가-대-정상-순서-평가brbr">인수 우선 평가 대 정상 순서 평가<br><br></h4>
<p>앞서 예시를 들었던 모든건 인수 우선 평가에 관한 얘기였음.<br><br></p>
<p>실제 평가 순서를 정의하고 이를 모델링 하는 방법에는 한가지 방법만 있는게 아닌데, 대표적인 대척점이 정상 순서 평가라고 하는 방법임<br><br></p>
<p>자바스크립트는 인수 우선 평가 방식으로 평가를 진행하니 그대로 알면 되고, 정상 순서 평가가 어디서 어떤 가치를 드러내는지는 4장에서 나온다고 한다.<br><br></p>
<p>정상 순서 평가를 지금 요약하자면, 계산을 전부 전개한뒤에 해당 계산을 한번에 수행하여 값을 도출하는 거임.<br><br></p>
<p>예를들어야 확실히 설명이 됨. 인수 우선평가는 f(6)을 만날때 일단 평가 먼저.(인수도 함께 평가가 된다는 거임.) 함수표현식: sum_of_square(x+1 , x+2) | 인수표현식: 6 -&gt; 적용! -&gt; sum_of_square(6+1, 6+2) -&gt; 평가! -&gt; 함수표현식:square(x) + square(y) | 인수표현식: 7, 8 -&gt; 적용! square(7) + square(8) -&gt; 이때 함수는 총 3개이므로(스퀘어2개 + 1개) 우선순위에따라 위의 행위를 반복한다. 즉 인수가 연산에 계속 직접 찹여함.<br><br></p>
<p>정상 순서 평가는 거대한 복합함수를 함수표현식만 계속 평가하며 쫙 전개하고 막판에 x를 대입한다고 생각하면 됨.
f(x) -&gt; sum_of_square(x +1, x+2) -&gt; square(x+1) + square(x+2) -&gt; ... 이런식으로해서 최종적으로 &quot;원시 계산 단계까지 전개한뒤에 원시 연산 조합을 통한 수행&quot;으로 대입해서 처리함.<br><br></p>
<p>겉으로 보기에는 정상 순서 평가가 뭔가 사람의 사고와 더 닮은 느낌인데, 프로그래밍적으로는 인수 우선 평가가 더 안전하다고 한다. 계산 순서에따라서 위법함이 나오는 경우가 있기 때문이라고 하는데 이는 뒤에 나온다고 한다...<br><br></p>
<h3 id="116--조건부-표현식과-술어brbr">1.1.6  조건부 표현식과 술어<br><br></h3>
<p>조건부 표현식이 뭐냐? 
조건부 + 표현식이다.
표현식이란: 컴퓨터가 하나의 값으로 이해하는 식이다.
정확히 표현하면 조건에따라서 결과값이 달라지는 식이 조건부 표현식이다.<br><br></p>
<p>조건문하고는 다르다. if else<del>~</del> 얘는 식 하나로 즉 누군가의 값이 될 수 있는 식 하나에 조건 판별이 들어간다는 뜻이다! 그래서 강력한거고 그래서 중요하다.<br><br></p>
<p>수학으로 따지면 절대값 연산이 있다. $|x|$ <br><br></p>
<p>술어 ? 귀결 표현식 : 대안 표현식<br><br></p>
<p>술어(predicate)란 결과값이 항상 boolean인 true || false 인 표현식을 술어라고 표현한다. primitive 타입 뿐만 아니라, 조합 or 함수 or 복합함수도 결국 boolean 값으로만 귀결이 된다면 술어로 사용이 가능하다.<br><br></p>
<p>조건부 표현식의 해석</p>
<ol>
<li>술어 평가(evaluate predicate)</li>
<li>귀결 표현식 평가 or 대안 표현식 평가.<br><br></li>
</ol>
<p>여기서 중요한건 평가이다. 평가를 받는건 표현식 뿐만이 아니다. 마찬가지로 함수나 복합함수도 전부 평가 받을 수 있는건 뭐든지 올 수 있다는 것! 게다가 평가를 통해 결과를 반환해야되는데 이를 길게 늘여 뜨려 중첩을 무한으로 이어 버릴 수도 있다. <br><br></p>
<p>p: 술어(값) e: 표현식(값) 일때<br><br></p>
<pre><code class="language-javascript">p1 ? e1 : e2;
p1 ? e1 : (p2 ? e2: e3);
p1 ? (p2 ? e2: e3) : p3 ? e4: e3;</code></pre>
<p>중첩의 예시이다. 우측 결합이란 점만 인식하고 정신 바짝 차리면 해결된다.  먼저 ?를 만난순간 ?의 결과를 나타내는 맨 오른쪽을 먼저 본다. 이후 오른쪽에 오는  ? : 를 기준으로 술어 ? 귀 : 대 관계를 파악하여 결과를 예측후 왼쪽으로 넘어간다. 다시 ? : 관계가 있다면 이를 반복하여 중첩을 평가한다.<br><br></p>
<p>정말 보기 힘들지만, 함수형 표현을 위해서는 상당히 자주 쓰이는 패턴이다.<br><br></p>
<p>원시 술어 연산자들 외에 복합 술어 연산자들에대해서도 볼필요가 있다. 이는 표현식의 값들을 단순히 같냐 크냐 다르냐로 비교하는게 아닌 논리가 같냐 논리가 다르냐 논리가 부정이냐 등 좀 더 고차원적인 결과를 내뱉기 때문이다.<br><br></p>
<ul>
<li>논리곱(logical conjunction): 술어 &amp;&amp; 술어. 술어? 술어: false 의 문법적 설탕(syntactic sugar)</li>
<li>논리합(logical disjunction): 술어 || 술어. 술어? true: 술어의 syntactic sugar</li>
<li>논리부정(logical negation): !술어<br><br></li>
</ul>
<h4 id="좀-더-깊게brbr">좀 더 깊게<br><br></h4>
<p>사칙 연산은 확실한 이항 연산자이다.
!는 논리부정으로 단항 연산자이다.
&amp;&amp;, || 는 연산자가 아니다.<br><br></p>
<p>엄밀하게 보면 따져보자. 연산자의 정의가 평가되고나서 인수 표현식을 이용해서 새로운 값을 정의하는게 연산자라고하면, 
논리곱과 논리합은 인수를 전부 평가하지 않고, 앞에 인수만 보고도 바로 결과표현식으로 귀결되는 단락 평가(short circuit evaluation) 현상이 일어나고, 이를 연산했다고 생각하지 않고, 제어흐름을 컨트롤하는 구문형으로도 해석할 수 있는거지.<br><br></p>
<p>공식문서에서 아무리 찾아봐도 전부 그냥 논리연산자라고만 지칭하지 엄밀하게 따지진 않았는데, SICP에서는 Operator라고 인정하고 있지는 않고 있다.<br><br></p>
<h3 id="연습문제brbr">연습문제<br><br></h3>
<h4 id="11-해석기-출력결과-쓰기brbr">1.1 해석기 출력결과 쓰기<br><br></h4>
<h5 id="나의-답변brbr">나의 답변<br><br></h5>
<pre><code>10
12
6
3 //a=3
4 //b=4
19
false
4 //자바스크립트에서 술어 %% 표현식에서 술어가 true라면 표현식으로 넘어가고 그냥 표현식의 결과가 답
16
6
16</code></pre><p><br><br></p>
<h5 id="오답노트brbr">오답노트<br><br></h5>
<pre><code>Welcome to Node.js v18.13.0.
Type &quot;.help&quot; for more information.
&gt; 10;
10
&gt; 5 + 3 + 4;
12
&gt; 9 - 1;
8
&gt; 6 / 2;
3
&gt; 2 * 4 + (4 - 6);
6
&gt; const a = 3;
undefined
&gt; const b = a + 1;
undefined
&gt; a + b + a * b;
19
&gt; a === b;
false
&gt; b &gt; a &amp;&amp; b &lt; a * b ? b : a;
4
&gt; a === 4 ? 6 : b === 4 ? 6 + 7 + a : 25;
16
&gt; 2 + (b &gt; a ? b : a);
6
&gt; (a &gt; b ? a : a &lt; b ? b : -1) * (a + 1);
16
&gt;</code></pre><h4 id="12-수식을-자바스크립트-표현식으로brbr">1.2 수식을 자바스크립트 표현식으로<br><br></h4>
<h5 id="나의-풀이brbr">나의 풀이<br><br></h5>
<pre><code>(5+4+(2-(3-(6+4/5)))) 
/
(3*(6-2)*(2-7));</code></pre><p><br><br></p>
<h4 id="13-세-개의-수를-받고-셋-중-가장-작은-것을-제외한-두-수의-제곱들을-합한-결과를-돌려주는-함수-선언brbr">1.3 세 개의 수를 받고 셋 중 가장 작은 것을 제외한 두 수의 제곱들을 합한 결과를 돌려주는 함수 선언<br><br></h4>
<pre><code class="language-js">function square(x){
        return x*x;
}
function sum(x,y){
        return x + y;
}
function solution(a,b,c){
//        const min = a &gt; b ? (b &gt; c ? &#39;c&#39; : &#39;b&#39; ) 
//    c&gt;b&gt;a            : c &gt; b ? &#39;a&#39; 
    //    b&gt;c&gt;a        : c &gt; a ? &#39;a&#39; : &#39;c&#39;;        
        return a &gt; b ? 
        (b &gt; c ? sum(square(a), square(b)) : sum(square(a), square(c))) 
        : c &gt; b ? sum(square(c), square(b)) 
        : c &gt; a ? sum(square(c), square(b)) : sum(square(a), square(b));    
}
solution(1, 2, 3);</code></pre>
<p><br><br></p>
<h4 id="14-앞에서-본-함수-적용-평가-모형은-함수-표현식-쪽이-복합함수여도-관계없다-다음-복합-함수-작동방식-서술brbr">1.4 앞에서 본 함수 적용 평가 모형은 함수 표현식 쪽이 복합함수여도 관계없다. 다음 복합 함수 작동방식 서술<br><br></h4>
<pre><code class="language-js">function plus(a,b){return a+b;}
function minus(a,b){return a-b;}
function a_plus_abs_b(a,b){
        return (b&gt;=0? plus: minus)(a,b);
}

/*
1. 일단 괄호를 만났으니 괄호 식을 평가 -&gt; 조건부 표현식임을 ?를 통해 확인 우측결합 우선순위를 이용해서 하나씩 요소들을 평가
2. 대안식:minus(환경에 정의된 함수명으로 평가됨), 귀결식:plus(환경에 정의된 함수명으로 평가됨), 술어:b가 양수면 true로 귀결
3. 인자인 b를 대입하여 첫번째() 괄호를 해결
4. 두번째괄호는 자연스레 함수명과 결합하여 합수 적용식이 됨.
5. 결론적으로 양수면 플러스 음수면 마이너스가 되어 함수명대로 a 더하기 절대값 b가 됨
*/</code></pre>
<p><br><br></p>
<h4 id="15-벤-빗디들--인수-우선-평가를-사용할때-정상-순서-평가를-사용할때-각각-어떤식으로-평가되는지를-서술brbr">1.5 벤 빗디들 ... 인수 우선 평가를 사용할때 정상 순서 평가를 사용할때 각각 어떤식으로 평가되는지를 서술<br><br></h4>
<pre><code class="language-js">function p() {return p();}
function test(x,y){
    return x===0? 0:y;
}
test(0, p());</code></pre>
<p>인수 우선 평가(일반적)</p>
<ol>
<li>test 평가: 함수식. 인수식 평가: 0, p() 함수식. 따라서 함수식 평가 하니 또 함수식. </li>
<li>return 적용(함수의 적용)</li>
<li>술어의 결과: true. 귀결식: 0. 대안식: p()</li>
<li>따라서 결과는 0</li>
</ol>
<p>정상 순서 평가(전부 전개하고 대입)</p>
<ol>
<li>test 전개: 0 === 0 ? 0 : p( )</li>
<li>대입하여 푸니 0?<br><br></li>
</ol>
<h5 id="solutionbrbr">solution<br><br></h5>
<p>핵심은 인수 우선평가는 인수를 확실하게 정의해서 다음 평가로 넘겨야되는데 P()가 무한루프이기때문에 무한루프에 빠진다는 것.<br><br></p>
<p>정상 순서 평가는 인수는 쳐다도 안보고 일단 전개해서 최종 식을 만든다음에 필요한 인수를 가져다가쓰기에<br><br></p>
<pre><code>if(x === 0){
        0
}else{
        p()
}</code></pre><p>의 형태를 만들고 대입만 하기에 결론적으로 p()가 호출이 안된다.<br><br></p>
<h3 id="117-제곱근-구하기brbr">1.1.7: 제곱근 구하기<br><br></h3>
<p>수학에서 제곱근 정의하는 방법과 이를 어떻게 구하는지를 선언하는 방법을 프로그래밍적으로 바로 옯길 수가 있나? -&gt; 결론적으로 없다. 왜냐하면 수학에서 하는 방식은 선언적 지식(declarative knowledge)이고, 프로그래밍에서 필요한 함수는 명령적 지식(imperative knowlege)이 필요하기 때문이다.<br><br></p>
<p>제곱하면 x가 되는 y를 뱉어라? 그래서 어떻게 뱉어야 되는데를 오차없이 알려줘야한다.<br><br></p>
<p>그걸 하는 방법이 뉴턴 매서드라고 하는 제곱근 구하는 공식이다.<br><br></p>
<p>제곱근을 알고 싶은 수: 피제곱근수
추측값: 제곱근에 근사한값
을 정의해두고, 계속해서 추측값을 제곱근에 가까운지 판별하며 루프를 끝내는 방법.<br><br></p>
<pre><code class="language-js">function square(x) { return x * x; }
function average(x, y) { return (x + y) / 2; }
function improve(guess, x) { return average(guess, x / guess); }
function abs(x) { return x &gt;= 0 ? x : -x; }
function is_good(guess, x, strength) {
    return abs(square(guess) - x) &lt; (0.1) / strength;
}
function sqrt_iter(guess, x, strength) {
    return is_good(guess, x, strength) ? guess 
           : sqrt_iter(improve(guess, x), x, strength);
}
function sqrt(x) {
    return sqrt_iter(1, x, 10);
}
sqrt(4);</code></pre>
<p><br><br></p>
<h3 id="연습문제brbr-1">연습문제<br><br></h3>
<h4 id="16brbr">1.6<br><br></h4>
<p>조건부 표현식이 보기 불편해서 조건부 표현식을 감싼 함수를 만들기로 함.</p>
<pre><code class="language-js">function conditional(predicate, then_clause, else_clause){
    retrun predicate ? then_clause: else_clause;
}</code></pre>
<p>이 때 이함수를 이용한 복합 함수를 만들어서 뉴튼식을 적용하여 제곱근을 구하려할때</p>
<pre><code class="language-js">function sqrt_iter(guess, x){
    return conditional(is_good_enough(guess, x), 
        guess, 
        sqrt_iter(improve(guess, x), x));
}</code></pre>
<p>이 함수로 제곱근을 구하려면 어찌될까?</p>
<pre><code class="language-js">function square(x) { 
    console.log(`square 함수 시작합니다. x: ${x}`);
    let result = x * x;
    console.log(`square(${x}) = ${result}`);
    return result; 
}

function average(x, y) { 
    console.log(`average 함수 시작합니다. x: ${x}, y: ${y}`);
    let result = (x + y) / 2;
    console.log(`average(${x}, ${y}) = ${result}`);
    return result; 
}

function improve(guess, x) { 
    console.log(`improve 함수 시작합니다. guess: ${guess}, x: ${x}`);
    let improved = average(guess, x / guess);
    console.log(`improve(${guess}, ${x}) = ${improved}`);
    return improved; 
}

function abs(x) { 
    console.log(`abs 함수 시작합니다. x: ${x}`);
    let result = x &gt;= 0 ? x : -x;
    console.log(`abs(${x}) = ${result}`);
    return result; 
}

function is_good_enough(guess, x) {
    console.log(`is_good_enough 함수 시작합니다. guess: ${guess}, x: ${x}`);
    let difference = abs(square(guess) - x);
    let result = difference &lt; 0.01;
    console.log(`is_good_enough(${guess}, ${x}) -&gt; |square(${guess}) - ${x}| = ${difference} -&gt; ${result}`);
    return result;
}

function conditional(predicate, then_clause, else_clause){
    console.log(`conditional 함수 시작합니다. predicate: ${predicate}`);
    let result = predicate ? then_clause : else_clause;
    console.log(`conditional 결과: ${result}`);
    return result;
}

function sqrt_iter(guess, x){
    console.log(`sqrt_iter 함수 시작합니다. guess: ${guess}, x: ${x}`);
    return conditional(
        is_good_enough(guess, x), 
        guess, 
        sqrt_iter(improve(guess, x), x)
    );
}

function sqrt(x) {
    console.log(`sqrt 함수 시작합니다. x: ${x}`);
    return sqrt_iter(1, x);
}

// 테스트 실행
console.log(`sqrt(10) 결과:`, sqrt(10));
</code></pre>
<p><br><br></p>
<p>실제 돌려보면 무한루프가 발생함. 원인은 모르겠음.. 잘 가다가 무슨 조건 때문인지 계속 호출이 맴돌음..<br><br></p>
<h4 id="16-solutionbrbr">1.6 Solution<br><br></h4>
<p>🎯 <strong>실제 함수를 구현해서 무한 루프가 발생하는 이유를 증명해보자!</strong></p>
<hr>
<h5 id="📌-1-무한-루프가-발생하는-이유-자바스크립트의-인수-우선-평가eager-evaluation"><strong>📌 1. 무한 루프가 발생하는 이유: 자바스크립트의 인수 우선 평가(Eager Evaluation)</strong></h5>
<p>자바스크립트는 함수를 호출할 때 <strong>&quot;인수 우선 평가&quot;</strong>를 한다.<br>👉 즉, <strong>함수의 본문이 실행되기 전에, 모든 인수(파라미터)들을 미리 계산해서 확정해놓고 실행한다!</strong>  </p>
<h5 id="✅-예제-1-함수-인수는-먼저-평가된다"><strong>✅ 예제 1: 함수 인수는 먼저 평가된다!</strong></h5>
<pre><code class="language-js">function test(a, b) {
    console.log(&quot;함수 실행됨!&quot;);
    return a + b;
}

console.log(test(1 + 2, 3 + 4));</code></pre>
<h5 id="📌-실행-과정"><strong>📌 실행 과정</strong></h5>
<ol>
<li><code>test(1 + 2, 3 + 4)</code>가 실행될 때  <ul>
<li>먼저 <code>1 + 2 = 3</code> 계산  </li>
<li>그리고 <code>3 + 4 = 7</code> 계산  </li>
<li><strong>결국 <code>test(3, 7)</code>이 실행된다!</strong>  </li>
</ul>
</li>
<li><code>&quot;함수 실행됨!&quot;</code> 출력  </li>
<li><code>test(3, 7)</code> → <code>3 + 7 = 10</code> 반환  </li>
</ol>
<blockquote>
<p><strong>🔥 결론:</strong> 자바스크립트는 <strong>함수의 인수를 미리 평가한 후에야 함수가 실행된다.</strong><br>즉, <strong>함수 본문에서 필요한 경우에만 실행되는 게 아니다!</strong>  </p>
</blockquote>
<hr>
<h5 id="📌-2-conditional-함수가-문제를-일으키는-이유"><strong>📌 2. <code>conditional</code> 함수가 문제를 일으키는 이유</strong></h5>
<p>자, 이제 문제의 핵심인 <strong><code>conditional</code> 함수</strong>를 보자.</p>
<pre><code class="language-js">function conditional(predicate, then_clause, else_clause) {
    return predicate ? then_clause : else_clause;
}</code></pre>
<p>일반적으로 우리가 생각하는 <code>if-else</code> 구조랑 비슷하게 보이지?<br>👉 그런데 <strong>자바스크립트의 인수 우선 평가 방식</strong> 때문에 문제가 발생한다!  </p>
<h5 id="✅-예제-2-conditional에서-예상치-못한-실행이-일어난다"><strong>✅ 예제 2: <code>conditional</code>에서 예상치 못한 실행이 일어난다!</strong></h5>
<pre><code class="language-js">function square(x) {
    console.log(`square(${x}) 호출됨`);
    return x * x;
}

console.log(conditional(true, square(3), square(4)));</code></pre>
<h5 id="📌-실행-과정-1"><strong>📌 실행 과정</strong></h5>
<ol>
<li><code>conditional(true, square(3), square(4))</code> 호출됨  </li>
<li><strong>인수 평가가 먼저 진행된다!</strong><ul>
<li><code>square(3)</code> 실행 → <code>square(3) 호출됨</code> 출력 → 9 반환  </li>
<li><code>square(4)</code> 실행 → <code>square(4) 호출됨</code> 출력 → 16 반환  </li>
</ul>
</li>
<li>이제 <code>predicate == true</code>이므로 <code>then_clause(9)</code> 반환  </li>
</ol>
<blockquote>
<p><strong>🚨 문제점:</strong>  </p>
<ul>
<li><code>predicate</code>가 <code>true</code>인데도 <strong><code>square(4)</code>가 실행되었다!</strong>  </li>
<li>즉, <strong>선택되지 않은 <code>else_clause</code>가 실행되는 것 자체가 문제!</strong>  </li>
<li><strong>이게 <code>sqrt_iter</code>에서 무한 루프를 만드는 원인이다.</strong></li>
</ul>
</blockquote>
<hr>
<h5 id="📌-3-sqrt_iter에서-무한-루프가-발생하는-이유"><strong>📌 3. <code>sqrt_iter</code>에서 무한 루프가 발생하는 이유</strong></h5>
<p>자, 이제 <strong>진짜 문제 코드</strong>를 보자.</p>
<pre><code class="language-js">function sqrt_iter(guess, x){
    console.log(`sqrt_iter 실행. guess: ${guess}, x: ${x}`);
    return conditional(
        is_good_enough(guess, x),
        guess,
        sqrt_iter(improve(guess, x), x)  // ⚠️ 여기서 이미 실행됨!
    );
}</code></pre>
<p>와... <strong>이제 문제의 원인이 보이지?</strong>  </p>
<h5 id="🚨-conditional을-실행하는-순간-sqrt_iterimproveguess-x-x가-먼저-실행된다"><strong>🚨 <code>conditional</code>을 실행하는 순간, <code>sqrt_iter(improve(guess, x), x)</code>가 먼저 실행된다!</strong></h5>
<p>👉 <strong>즉, <code>is_good_enough(guess, x)</code>가 <code>true</code>든 <code>false</code>든 상관없이 <code>sqrt_iter</code>이 무조건 실행된다!</strong>  </p>
<hr>
<h5 id="📌-4-sqrt_iter1-10이-어떻게-무한-루프에-빠지는가"><strong>📌 4. <code>sqrt_iter(1, 10)</code>이 어떻게 무한 루프에 빠지는가?</strong></h5>
<h5 id="🔍-함수-호출-과정"><strong>🔍 함수 호출 과정</strong></h5>
<pre><code>sqrt(10) 호출
    ├── sqrt_iter(1, 10) 호출
        ├── conditional(
                is_good_enough(1, 10) → false,
                1,
                sqrt_iter(5.5, 10) → 이미 실행됨 ❌
            )
        ├── sqrt_iter(5.5, 10) 호출됨 (이미 평가됨)
            ├── conditional(
                    is_good_enough(5.5, 10) → false,
                    5.5,
                    sqrt_iter(3.659, 10) → 이미 실행됨 ❌
                )
            ├── sqrt_iter(3.659, 10) 호출됨 (이미 평가됨)
                ├── conditional(
                        is_good_enough(3.162, 10) → true,
                        3.162,
                        sqrt_iter(3.162, 10) → 이미 실행됨 ❌
                    )
                ├── sqrt_iter(3.162, 10) 호출됨 (이미 평가됨)
                    ├── (무한 루프)</code></pre><p><strong>🔥 결론:</strong><br>👉 <strong>조건문이 <code>true</code>가 되어도 이미 실행된 <code>sqrt_iter</code>이 계속해서 새로운 재귀를 만들기 때문에 무한 루프가 발생한다.</strong>  </p>
<hr>
<h5 id="📌-5-해결-방법-if-else로-바꾸면-해결된다"><strong>📌 5. 해결 방법: <code>if-else</code>로 바꾸면 해결된다!</strong></h5>
<h5 id="🚀-if-else를-사용하면-어떻게-되는가"><strong>🚀 <code>if-else</code>를 사용하면 어떻게 되는가?</strong></h5>
<pre><code class="language-js">function sqrt_iter(guess, x){
    console.log(`sqrt_iter 실행. guess: ${guess}, x: ${x}`);
    if (is_good_enough(guess, x)) {
        return guess;  // ✅ 여기서 즉시 종료됨!
    } else {
        return sqrt_iter(improve(guess, x), x);
    }
}</code></pre>
<h5 id="🔍-이제-스택이-어떻게-정리되는가"><strong>🔍 이제 스택이 어떻게 정리되는가?</strong></h5>
<ol>
<li><code>is_good_enough(3.162, 10) == true</code>이면 즉시 종료됨.</li>
<li><code>sqrt_iter</code> 재귀 호출이 멈추고, 정상적으로 <code>sqrt(10) = 3.162</code> 반환됨.</li>
</ol>
<hr>
<h5 id="🔥-최종-결론"><strong>🔥 최종 결론</strong></h5>
<p>✅ <strong>&quot;자바스크립트의 인수 우선 평가 방식 때문에 <code>conditional</code>을 사용할 경우, <code>else_clause</code>가 필요 없을 때도 평가되어 무한 루프가 발생한다.&quot;</strong><br>✅ <strong>&quot;즉, <code>is_good_enough(guess, x)</code>가 <code>true</code>가 되어도 이미 <code>sqrt_iter</code>이 실행되었기 때문에 탈출하지 못하는 것이다.&quot;</strong><br>✅ <strong>&quot;이를 해결하려면 <code>if-else</code>를 사용해서 <code>is_good_enough(guess, x)</code>가 <code>true</code>일 때 즉시 반환하도록 해야 한다.&quot;</strong> 🚀🔥<br><br><br></p>
<h4 id="17brbr">1.7<br><br></h4>
<p>제곱근 계산에 쓰인 is_good_enough 술어의 판정 방식은 아주 작은 수의 제곱근을 구할 때는 그리 효과적이지 않다. 
그리고 실제 컴퓨터에서 산술 연산은 거의 항상 정밀도(유효자릿수)가 제한된 상태로 수행되기 때문에, is_good_enough의 판정 방식은 아주 큰 수의 제곱근 계산에도 부적합하다. </p>
<p>*<em>이러한 점을 좀 더 자세히 설명하고, 작은 수와 큰 수에 대해 판정이 실패하는 사례들을 제시하라. *</em></p>
<p>is_good_enough를 구현하는 또 다른 전략은 <strong>반복 과정</strong>에서 <strong>guess의 변화량</strong>을 추적하면서 변화량이 <strong>guess의 아주 작은 비율보다 작으면</strong> 충분히 좋은 추측값이라고 판정하는 것이다. </p>
<p><strong>이런 종류의 반복 종료 판정 방식을 사용하는 제곱근 함수를 설계하라.</strong></p>
<p>작은 수와 큰 수에 대해 그 함수가 본문의 함수보다 더 잘 작동하는가?<br><br></p>
<h5 id="나의-풀이brbr-1">나의 풀이<br><br></h5>
<pre><code class="language-js">//실험 기존 코드
function sqrt(x){ return sqrt_iter(1, x); }
function sqrt_iter(guess, x){ 
    return is_good(guess, x) ? guess:sqrt_iter(improve(guess, x), x);
}
function is_good(guess, x){ return abs(square(guess) - x) &lt; 0.001; }
function improve(guess, x){ return average(guess, x/guess); }
function abs(x){ return x &lt; 0 ? -x : x; }
function square(x){ return x*x; }
function average(a, b){ return (a+b)/2; }

//작은 경우
sqrt(0.01); //기대값: 0.1 -&gt; 실험값: 0.10032578510960605
sqrt(0.0001); //기대값: 0.01 -&gt; 실험값: 0.03230844833048122 //고장시작
sqrt(0.00001); //기대값: 0.001 -&gt; 실험값: 0.031260655525445276 //완전고장
sqrt(0.001); //실험값: 0.04124542607499115 //이미 많이 벗어남.
//결론: is_good에서 x가 0.001보다 작게 되면 적당히 제곱해서 0.001보다 작은수랑 x빼서 실제로 작으면 트루로 반환하는게 문제. 즉 0.001로 비교하기엔 x값이 0.001에 가까워질수록 정확한 계산 불가

//큰 경우
sqrt(10000) //기대값: 100 -&gt; 실험값: 100
sqrt(1000000) //기대값: 1000 -&gt; 실험값: 1000
sqrt(900000000) //기대값: 30000 -&gt; 실험값: 30000
sqrt(987654321987654321); //Maximum call stack error
sqrt(9000000000000000000); //실험값: 3000000000 -&gt; 오히려 큰수여도 딱 떨어지는 숫자를 주면 콜스택 에러가 안난다.
//결론: 0.001이라는 고정된 팩터가 근사값을 측정하기까지 너무 많은 연산을 해야되기 때문에 제대로된 연산 결과에 도달을 못한다.</code></pre>
<pre><code class="language-js">//새로 제시된 방식: guess의 변화량이 guess의 아주 작은 비율보다 작으면 충분히 좋은값
function sqrt(x){ return sqrt_iter(x, 1, x); }
function sqrt_iter(pre, guess, x){ 
    return is_good(pre, guess) ? guess:sqrt_iter(guess, improve(guess, x), x);
}
function is_good(pre, guess){ return abs(pre - guess) &lt; (guess*0.00001); }
function improve(guess, x){ return average(guess, x/guess); }
function abs(x){ return x &lt; 0 ? -x : x; }
function square(x){ return x*x; }
function average(a, b){ return (a+b)/2; }

sqrt(987654321987654321);//993807990.5030237 -&gt; 이제 에러가 안난다. 기대값과도 일치</code></pre>
<p><br><br></p>
<h4 id="■-연습문제-18">■ 연습문제 1.8</h4>
<p>세제곱근을 위한 뉴턴 방법에서는, y가 x의 세제곱근을 근사하는 값이라고 할 때 다음 공식으로 디 나은 근삿값을 구한다.
$\frac{{x/y^2+2y}}{3}$
이 공식을 이용해서 제곱근 함수와 비슷한 형태의 세제곱근 함수를 구현하라. ($1.3.4에서는
이 제곱근 함수와 세제곱근 함수를 추상화한 것에 해당하는, 일반적인 뉴턴 방법의 구현을 이
야기한다.)<br><br></p>
<h5 id="나의-풀이">나의 풀이</h5>
<pre><code class="language-js">    function th_sqrt(x){ return th_sqrt_iter(x, 1, x); }
    function th_sqrt_iter(pre, guess, x){
        return th_is_good(pre, guess) ? guess :
            th_sqrt_iter(guess, th_improve(guess,x), x);
    }
    function th_is_good(pre, guess){ return abs(pre-guess)&lt; guess*0.0001;}
    function th_improve(guess, x){
        return (x/(guess*guess) + 2*guess)/3;
    }
    function abs(x){return x &lt; 0 ? -x : x; }
    th_sqrt(27); //실행값: 3
    th_sqrt(987654321); //이론값: 995.86772 실행값: 995.8677216529971
    th_sqrt(0.0000123456789); //실행값:0.023112042410213075 이론값:0.02311...</code></pre>
<p><br><br></p>
<h3 id="118-블랙박스-추상으로서의-함수brbr">1.1.8 블랙박스 추상으로서의 함수<br><br></h3>
<p>함수의 군집을 만들때 필요한 함수를 분해하는 전략
    - 각 함수들이 각자 식별 가능한 과제를 수행: 확실하게 구분되어야함. 비슷한 일을 하는거면 의미 없음
    - 그 함수들을 모듈로서 사용해서 다른 함수의 정의에 사용할 수 있게 하는 것
-<strong>정리: &quot;모듈(module)&quot;이란?</strong></p>
<blockquote>
<p><strong>&quot;하나의 특정한 역할을 수행하는 독립적인 함수 또는 코드 단위&quot;</strong><br><strong>&quot;다른 함수에서 재사용 가능하며, 조립할 수 있는 작은 구성 요소&quot;</strong></p>
</blockquote>
<p><strong>square가 구체적인 함수가 아니라 함수의 추상이다?&quot;</strong></p>
<p>좋아, 이걸 제대로 이해하려면 <strong>&quot;구체적인 함수(concrete function)&quot; vs &quot;함수적 추상(functional abstraction)&quot;</strong> 의 차이를 먼저 알아야 한다. 관념적인 내용이다. 똑같은 함수인데도 구체적인 함수가 될수도 있고 함수적 추상이 될수도 있다는 거야<br><br></p>
<pre><code class="language-js">function square(x) {
    return x * x;
}</code></pre>
<p>이거는 함수의 정의, 구현부이다. 이렇게 바라보는게 구체적인 함수야.</p>
<pre><code class="language-js">function is_good_enough(guess, x) {
    return Math.abs(square(guess) - x) &lt; 0.01;
}</code></pre>
<p>이제 이렇게 바라보는게 함수적 추상이다.<br><br></p>
<p>무슨 차이냐면. 함수적 추상은 안에 세부적인 내용은 모르겠고(연산, 구현, 부품의 원리, 요소가 어떻게 이루어져서 뭐시기 이런거) 그냥 얘를 이용하면 제곱이 되겠거니 생각하겠다 이거야.<br><br></p>
<p>그래서 책에서 말하는 is_good_enough 입장에서 square는 하나의 함수 추상이다. 라는 말이 그뜻이야.<br><br></p>
<p>그래서 그걸 블랙박스 추상으로서의 함수라고 말하는거야<br><br></p>
<h4 id="local-name지역이름brbr">local name(지역이름)<br><br></h4>
<ul>
<li>함수의 사용자는 함수의 구체적인 내용을 몰라도 된다. : 함수적 추상</li>
<li>그 말은 즉 함수의 매개변수의 이름을 몰라도 된다는 얘기이다. 이런 함수의 매개변수들을 함수 본문 안에서만 유효한 local name 이라고 함.</li>
<li>만약 local name을 지원하지 않았다면? -&gt; 변수 선언 대혼란의 시대가 도래함</li>
<li>local name을 가능하게 하는 원리? -&gt; bounding을 지원하기 때문. 함수안에서 종속되게 만든는거</li>
<li>주어진 이름의 유효한 범위를 scope라고함. 함수의 매개변수는 함수 구현부가 scope이다.</li>
<li>bounding, bound의 개념은 함수 안에서만 있는건 아니고 넓게 더 퍼져있다. 그러나 여기서는 이정도만<br><br></li>
</ul>
<h4 id="내부-선언과-블록-구조brbr">내부 선언과 블록 구조<br><br></h4>
<ul>
<li><p>isolation: 격리.</p>
</li>
<li><p>지금까지 배운 격리 방식: local name 매개변수<br><br></p>
</li>
<li><p>그런데 지금까지 배운 함수들이 더 대형 시스템 안에서 공존한다고 상상</p>
</li>
<li><p>프로그램 개발할때마다 이런 함수가 있나? 저런함수가 있나? 계속 isolation 시키기위한 고민을 끊임없이 해야함.</p>
</li>
<li><p>그것을 편하게 해주는게 복합함수 안에 보조함수를 넣는 방식.<br><br></p>
</li>
<li><p>복합함수: 여러 함수들을 조합하여 동작하는 함수</p>
</li>
<li><p>보조함수: 복합함수 연산에 참여하여 필요한 부품들</p>
</li>
</ul>
<pre><code class="language-js">//여러 보조함수들을 {} 중괄호 쌍에 포함시켜 버리면서 해당 함수들은 이제 sqrt()의 local name이 되었다!!
function sqrt(x){
    function is_good_enough(guess, x){
        return abs(square(guess) - x) &lt; 0.001;
    }
    function improve(guess, x) {
        return average(guess, x / guess);
    }
    function sqrt_iter(guess, x) {
        return is_good_enough(guess, x)
            ? guess
            : sqrt_iter(improve(guess, x), x);
    }
    return sqrt_iter(1, x);
}

//-&gt; 더 간편화된 방법. 애초에 x를 여러번 매개변수로 쓸 필요가 없다. 왜? x는 sqrt 선언에 대한 바인딩 name 이므로, 같은 바인딩된 function들은 x를 자유자재로 사용가능하다.
// 이러한 방식을 어휘순 범위 적용(lexical scoping)이라고 한다.
// 대형 시스템을 편하게 해준다.
// 어차피 사용자 혹은 응용프로그래머가 알아야될 내용은 sqrt(x)라는 함수명 하나일 뿐이다.</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[방송대_디지털논리회로_1강]]></title>
            <link>https://velog.io/@flower-in-eyes/%EB%B0%A9%EC%86%A1%EB%8C%80%EB%94%94%EC%A7%80%ED%84%B8%EB%85%BC%EB%A6%AC%ED%9A%8C%EB%A1%9C1%EA%B0%95</link>
            <guid>https://velog.io/@flower-in-eyes/%EB%B0%A9%EC%86%A1%EB%8C%80%EB%94%94%EC%A7%80%ED%84%B8%EB%85%BC%EB%A6%AC%ED%9A%8C%EB%A1%9C1%EA%B0%95</guid>
            <pubDate>Mon, 17 Mar 2025 13:35:53 GMT</pubDate>
            <description><![CDATA[<h2 id="1장-컴퓨터와-디지털-논리-회로brbr">1장 컴퓨터와 디지털 논리 회로<br><br></h2>
<h3 id="01-디지털-시스템brbr">01 디지털 시스템<br><br></h3>
<h4 id="시스템의-정의brbr">시스템의 정의<br><br></h4>
<p>시스템: 어떤 목적을 위해 서로 상호작용하는 구성요소들의 집합.<br><br></p>
<p>컴퓨터 시스템, math 시스템, 사회 시스템 등등<br><br></p>
<p>시스템을 사용하는 <code>사용자</code>의 관심 정도에 따라서 얼마나 상세하고 디테일하게 분석할지가 달라진다<br><br></p>
<p><strong>시스템의 분류</strong></p>
<ol>
<li>블랙 박스형 시스템: 가장 단순한 형태. 입력과 출력만이 관심 있음.<code>일반 사용자</code>가 주로 관심 대상이다.</li>
<li>구성요소의 집합으로서의 시스템: 외부 입력을 어떻게 출력으로 반환할지. 그 전개 방식에 관심이 있는 사람들의 시스템 분류법. <code>프로그래머</code>는 컴퓨터 시스템을 바라볼때 구성요소의 집합으로서 분류할 줄 알아야 함.<br><br></li>
</ol>
<h4 id="아날로그와-디지털brbr">아날로그와 디지털<br><br></h4>
<p>컴퓨터 시스템 뿐만 아니라 여러 시스템들은 구성요소들을 가지고 있는데 보통 데이터라는 요소가 있다. 그 데이터를 표현하는 방식에는 아날로그와 디지털이 있음<br><br></p>
<p>아날로그 방식</p>
<ul>
<li>연속적인 값. 값을 정확히 읽을 수 없는 개념이 존재함. 예를들어 무한소수</li>
<li>수학 시스템, 자연 시스템 등</li>
<li>아날로그 측정기(체중계, 전력 사용량 검출기), 라디오 주파수 다이얼(아날로그 방식의 경우엔 정확히 정수로 떨어지는 값이 아닌 무한 소수 값들도 맞추는게 가능)<br><br></li>
</ul>
<p>디지털 방식</p>
<ul>
<li>명확히 나뉘는 값인 이산 값(Discrete Value) 개념. 예를들어 정수</li>
<li>정수 시스템, 컴퓨터 시스템 등 </li>
<li>컴퓨터의 경우엔 특정 값을 2가지를 놓고, 0<del>0.4V 까지는 그냥 0 , 2.5</del>5V까지는 그냥 1로 딱딱 끊어서 해석한다.<br><br></li>
</ul>
<table>
<thead>
<tr>
<th>아날로그 시스템</th>
<th>디지털 시스템</th>
</tr>
</thead>
<tbody><tr>
<td>입력과 출력이 아날로그 데이터인 시스템</td>
<td>입력과 출력이 디지털 데이터인 시스템</td>
</tr>
<tr>
<td>눈금과 바늘 등으로 값을 확인하는 계기 시스템들</td>
<td>정확한 값이 딱 떨어지는 전자식 계기 시스템</td>
</tr>
<tr>
<td>------</td>
<td>-----</td>
</tr>
</tbody></table>
<p>디지털 시스템의 장점</p>
<ul>
<li>편리성: 데이터가 숫자로 바로 입출력이 되어 <code>인식이 편리</code>하다</li>
<li>융통성: 외부 조건의 변화에 <code>융통적으로 실행 순서 조절</code>이 가능</li>
<li>단순성: 0과 1, 두 가지 상태의 신호만 취급하기에 자연계를 표현하기에 <code>단순</code>해진다.</li>
<li>안정성: 0과 1, 두 가지 상태의 신호만 유지하면 되기에 그 사이 무수히 많은 변수에 대하여 <code>안정</code>적</li>
<li>견고성: 0과 1, 두 가지 상태로 전송되어 중간 잡음에 대하여 <code>견고</code></li>
<li>정확성: 신호를 이산 신호로 변환하기에 상대적으로 오류에 <code>정확</code><br><br></li>
</ul>
<h4 id="디지털-시스템의-설계-및-논리회로brbr">디지털 시스템의 설계 및 논리회로<br><br></h4>
<ul>
<li><p>디지털 시스템 설계 전체 단계
요구사항 분석 -&gt; 사양정리 -&gt; <code>디지털 시스템 설계</code> -&gt; 프로토 타입 제작 -&gt; 테스트 및 디버깅 -&gt; 생산<br><br></p>
</li>
<li><p>디지털 시스템 설계 단계의 구체적인 순서
회로 설계 -&gt; 논리 설계 -&gt; 시스템 설계 -&gt; 실제적 설계<br><br></p>
</li>
</ul>
<p>회로 설계(curcuit design): 논리 소자(logic gate)를 만들기 위해 능동소자와 수동소자를 연결하는 단계 -&gt; 생산물: 논리소자 -&gt; 마치 원시 타입, 원시 함수를 만드는 것과 비슷<br><br></p>
<p>논리 설계(logic design): 논리회로를 만들기 위해 논리소자들을 연결하는 단계 -&gt; 생산물: 논리 회로 -&gt; 마치 사용자 클래스들 같은 느낌쓰<br><br></p>
<p>시스템 설계(system design): 논리회로, 기억장치 등을 조합해서 프로세서, 입출력 제어장치 등을 설계하는 단계 -&gt; 생산물: 디지털 시스템 -&gt; 전체 프로그래밍 같은 느낌<br><br></p>
<p>실제적 설계(physical design): 시스템 설계 단계의 결과물을 PCB기판이나 와이어랩에 설치하는 단계 -&gt; 생산물: 디지털 시스템의 실물화 -&gt; 프로그램 빌드해서 실행파일 만들어서 설치하는 느낌<br><br></p>
<h5 id="용어가-너무-햇갈린다brbr">용어가 너무 햇갈린다<br><br></h5>
<p>회로설계(논리 소자를 만듬) -&gt; 논리설계(논리 회로를 만듬) -&gt; 시스템 설계(디지털 시스템을 만듬) -&gt; 실제적설계(제품을 만듬)<br><br></p>
<p>이 기본골자를 가져간 채로 들어간다.<br><br></p>
<h5 id="디지털-논리회로의-개요brbr">디지털 논리회로의 개요<br><br></h5>
<ul>
<li>디지털 논리 회로란?<ul>
<li>디지털 논리 개념을 논리 게이트를 이용하여 구현한 것<ul>
<li>즉 하나 이상의 논리 게이트(논리 소자)들이 조합되어 만들어지겠지</li>
</ul>
</li>
<li><strong>논리 설계 단계의 결과물</strong>이고, 만들어진 결과물인 <strong>논리 회로가 디지털 시스템의 가장 작은 단위의 기본 요소</strong><ul>
<li>즉 논리 회로까지도 안가면 디지털 시스템에 끼지도 못한다. 즉 간단한 논리 게이트는 그냥 수단일뿐 실질적 의미는 논리 회로가 만들어져야 시스템의 부품으로서 그 역할을 하게 된다.</li>
</ul>
</li>
</ul>
</li>
<li>저장 요소의 유무에 따른 분류<ul>
<li>조합논리회로: 저장요소 없이 연산만 하겠지 -&gt; 가산기, 디코더</li>
<li>순서논리회로: 저장요소가 있어야 순서를 조작하지 -&gt; 레지스터, 카운터<br><br></li>
</ul>
</li>
</ul>
<h3 id="02-컴퓨터-구성brbr">02 컴퓨터 구성<br><br></h3>
<h4 id="컴퓨터-시스템brbr">컴퓨터 시스템<br><br></h4>
<ul>
<li><p>전자식 데이터 처리 시스템(Electronic Data Processing System)이라고 한다.</p>
<ul>
<li>기본요소 : 사람, 하드웨어, 프로시저, 소프트웨어, 데이터</li>
<li>위 중 하나도 없다면 시스템의 기본 요소가 없는 것이므로 의미 없는 시스템이 된다. <ul>
<li>이 중에서 사람이 제일 의미 없어 보이긴 하는데 24시간 자동으로 돌아가는 시스템이라도 사람이 입력을 통해 동작을 시킨거고, 인공지능도 같은 맥락이므로 컴퓨터 시스템의 기본요소에는 사람이 들어간다.<br><br></li>
</ul>
</li>
</ul>
</li>
<li><p>컴퓨터를 시스템 측면에서 분석: 컴퓨터 공학에서 바라볼때의 기본</p>
<ul>
<li>구성요소는 무엇인가?</li>
<li>각 구성 요소는 어떤 기능을 갖는가?</li>
<li>입출력은 무엇인가?<br><br></li>
</ul>
</li>
</ul>
<h4 id="컴퓨터-하드웨어-구성brbr">컴퓨터 하드웨어 구성<br><br></h4>
<p>입력장치, 제어장치, 기억장치, 연산장치, 출력장치<br><br></p>
<h3 id="03-집적-회로brbr">03 집적 회로<br><br></h3>
<h4 id="집적회로ic-intergrated-circuits의-개요brbr">집적회로(IC: Intergrated Circuits)의 개요<br><br></h4>
<ul>
<li><p>집적회로(IC or Chip or sillicon semiconductor crystal)</p>
<ul>
<li>디지털 회로의 구성 요소</li>
<li>디지털 게이트의 기능을 수행하는 전자 소자를 포함한 실리콘 반도체 크리스탈</li>
<li>내부에 여러 게이트들이 목적에 부합되도록 상호 연결되어 있는 상태<ul>
<li>즉 이 자식은 논리 설계 단계의 부산물로 디지털 시스템의 기본 구성 요소이다.<br><br></li>
</ul>
</li>
</ul>
</li>
<li><p>집적도(level of intergration)</p>
<ul>
<li>실리콘 칩의 단위 면적당 집적할 수 있는 전자 소자(gate)의 수를 표현하는 개념</li>
</ul>
</li>
</ul>
<table>
<thead>
<tr>
<th>집적도</th>
<th>소자 수</th>
</tr>
</thead>
<tbody><tr>
<td>소규모 집적(Smal Scale Intergration)</td>
<td>계산기, 전자시계</td>
</tr>
<tr>
<td>중규모 집적(Medium SI)</td>
<td>레지스터, ALU, 디코더, 멀티플렉스</td>
</tr>
<tr>
<td>대규모 집적(Large SI)</td>
<td>초기 마이크로프로세서, 메모리 칩</td>
</tr>
<tr>
<td>초대규모 집적(Very Large SI)</td>
<td>현대 마이크로프로세서, GPU, SoC</td>
</tr>
</tbody></table>
<ul>
<li>디지털 논리계열(Digital Logic Famillies)<ul>
<li>게이트를 만들때 기술이나 전압 전류 등 여러 특성들 중 비슷한 애들끼리 묶는 개념.</li>
<li>정의: 디지털 논리 회로 설계에 사용되는 논리 소자의 집합</li>
<li>아래 표는 이런게 있다 정도만 알고 넘어가</li>
</ul>
</li>
</ul>
<table>
<thead>
<tr>
<th>디지털 논리계열</th>
<th>응용 분야</th>
<th>대표회로</th>
</tr>
</thead>
<tbody><tr>
<td>TTL(Transistor-Transistor Logic)</td>
<td>초기 디지털 컴퓨터</td>
<td>NAND 게이트</td>
</tr>
<tr>
<td>ECL(Emitter-Coupled Logic)</td>
<td>고속 통신 시스템</td>
<td>NOR 게이트</td>
</tr>
<tr>
<td>NMOS(N-channel Metal-Oxide-Semiconductor)</td>
<td>초기 마이크로프로세서</td>
<td>NAND 게이트</td>
</tr>
<tr>
<td>CMOS(Complementary Metal-Oxide-Semiconductor)</td>
<td>현대 마이크로프로세서</td>
<td>인버터</td>
</tr>
</tbody></table>
<h4 id="양논리와-음논리brbr">양논리와 음논리<br><br></h4>
<ul>
<li>양논리와 음논리<ul>
<li>디지털 시스템은 크기 2가지 논리 시스템을 사용한다.</li>
<li>논리값에 대하여 실제 논리를 어떤 전기적 신호값을 사용할지 선택하는 방식.</li>
<li>양논리: 높은게 1, 낮은게 0</li>
<li>음논리: 높은게 0, 낮은게 1<br><br></li>
</ul>
</li>
</ul>
<h2 id="2장-데이터-표현brbr">2장 데이터 표현<br><br></h2>
<h3 id="2-1-수치-데이터brbr">2-1 수치 데이터<br><br></h3>
<h4 id="2-1-1-진법brbr">2-1-1 진법<br><br></h4>
<ul>
<li>진법 정의: 수를 특정 기수(base)를 기반으로 숫자의 조합으로 표현하는 체계<ul>
<li>기수: 진법에서 자리값의 기준이 되는 값. 한 자리에서 표현할 수 있는 숫자의 크기(or 개수)</li>
<li>숫자의 위치에 따라서 각 숫자가 실제 값을 결정함.</li>
<li>가중치: 자리수. 기수의 승수로 계산.</li>
</ul>
</li>
<li>r 진법<ul>
<li>기수가 r인 경우 r진법. r진법으로 표현된 수를 r진수</li>
<li>각 자리는 r개의 숫자가 올 수 있음 (0~r-1)</li>
<li>r진수 오른쪽 아래첨자로 기수 r을 표현</li>
</ul>
</li>
<li>r 진법을 10진법으로 바꾸는 법 -&gt; 그냥 곱해서 더해</li>
<li>컴퓨터에서의 대표적인 진법<ul>
<li>2진수(Binary)<ul>
<li>전기 신호의 ON/OFF 를 표현하기 가장 유리한 숫자 체계</li>
</ul>
</li>
<li>8진수(Octal)<ul>
<li>2진수를 축약하기 좋음</li>
<li>리눅스의 파일권한 정보가 3비트이고 3비트를 한 숫자로 표현하기 위해 8진수로 요약됨</li>
</ul>
</li>
<li>16진수(Hexadecimal)<ul>
<li>헥사코드. 메모리 주소, 색상 코드 등 2진수를 변환하면서 동시에 현대 알파벳과 결합하여 표기하기 좋은 진법</li>
</ul>
</li>
</ul>
</li>
<li>10진수를 r진수로 변환: 2진수로 변환한뒤에 역으로 8진수 16진수 등으로 변환<ul>
<li>정수부: 2로 계속 나눈 나머지를 나열</li>
<li>실수부: 실수부가 0이 될때까지 계속 2를 곱하면서 나온 정수 자리를 나열<ul>
<li>8진수는 2진수 3자리씩 </li>
<li>16진수는 2진수 4자리씩</li>
</ul>
</li>
</ul>
</li>
<li>산술연산<ul>
<li>그냥 10진수로 변환후에 계산하고 다시 r진수로 변환하는 방식으로 풀면 공식 따로 필요없이 모든 연산 가능<br><br></li>
</ul>
</li>
</ul>
<h4 id="2-1-2-보수brbr">2-1-2 보수<br><br></h4>
<ul>
<li><p>보수(complement): 보충해 주는 수</p>
<ul>
<li>주어진 숫자가 특정 기준 값에서 얼마나 떨어져 있는지를 나타내는 값<ul>
<li>10진수 7에 대한 10의 보수는 3 -&gt; 10-7</li>
<li>10진수 70에 대한 10의 보수는 30 -&gt; 100-70</li>
</ul>
</li>
<li>기수가 r인 수 체계에서는 진보수인 r의 보수와 (r-1)의 보수가 존재함<br><br></li>
</ul>
</li>
<li><p>r의 보수</p>
<ul>
<li>N에 대한 r의 보수 정수 부분이 n자리라면</li>
<li>$r^n-N$<ul>
<li>2진수 110111의 2의 보수는</li>
<li>총 6자리 따라서 $2^6보수=1000000-110111=111112-110111=001001$<br><br></li>
</ul>
</li>
</ul>
</li>
<li><p>r-1의 보수</p>
<ul>
<li>N에 대한 (r-1)의 보수 정수 부분이 n자리라면</li>
<li>$r^n-1-N$<ul>
<li>2진수 110111의 2의 보수는 6자리니까 그냥 111111에서 N을 빼주니 1-&gt;0, 0-&gt;1한 결과</li>
<li>10진수 83의 9의 보수는 99-83=16</li>
<li>r-1의 보수가 유용한 점은 r의 보수를 구하기 쉬운 버전이라는 점이다. 자리올림 내림 고려할 필요없이 각 자리에서 올 수 있는 가장 큰수에서 해당 숫자를 빼면 되기 때문.<br><br></li>
</ul>
</li>
</ul>
</li>
<li><p>r의 보수와 r-1의 보수의 관계</p>
<ul>
<li>r-1의 보수에서 +1을 한게 r의 보수이다. 즉 r의 보수를 구하기 쉬운 방법이다. 앞으로 항상 r-1의 보수에서 +1을 해서 구하도록 하자!<br><br></li>
</ul>
</li>
<li><p>보수의 쓰임새</p>
<ul>
<li>컴퓨터는 가산기만으로 모든 연산을 처리해야한다. 따라서 뺄셈을 보수로 바꾸어 더한뒤에 자리올림을 버리는 형태로 뺄셈을 구현한다.</li>
<li>10진수 156-5 <ul>
<li>항상 가장 자리수가 많은 수보다 한자리가 무조건 늘어나게 되므로 그냥 버려주면 된다.  Why? 보수의 정의가 n자리수의 보수는 $r^n$이 되기 위한 보충하는 수이므로...</li>
<li>실제 보수를 이용한 감산 연산 원리 <ul>
<li>156-5 -&gt; 156 - 005 -&gt; 156 + 994 -&gt; 1150 -&gt; 1150+1 -&gt; 1151 -&gt; 151<br><br></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="2-2-디지털-코드brbr">2-2 디지털 코드<br><br></h3>
<h4 id="2-2-1-10진-코드brbr">2-2-1 10진 코드<br><br></h4>
<ul>
<li>10진수를 나타내는 2진 코드 (BCD 코드)<ul>
<li>목적: 해당 코드들은 10진수 하나 즉 0~9 까지의 숫자 개념을 컴퓨터에서 저장하고 표현하기 위한 방법이다. 4비트. 여러 표준들이 있고 그렇게 표현하는 뭐 의미가 있겠지만, 목적만 알고 넘어가자</li>
<li>종류: BCD8421, BCD2421, BCD84-2-1, Excess-3, Gray<br><br></li>
</ul>
</li>
</ul>
<h4 id="2-2-2-영-숫자-코드brbr">2-2-2 영 숫자 코드<br><br></h4>
<p>문자 숫자 코드<br><br></p>
<ul>
<li>ASCII 코드: 7비트(문자 총 128개 표현) + 1비트(패리티 비트)</li>
<li>EBCDIC: BCD에서 확장 되었다. 그정도만..</li>
<li>유니코드: 영문뿐만 아니라 모든 문자를 다루기 위한 표준 코드(UTF-8, UTF-16)  등이 있고 가변임.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[혼공컴운_6주차_CH14_CH15 가상 메모리, 파일 시스템]]></title>
            <link>https://velog.io/@flower-in-eyes/%ED%98%BC%EA%B3%B5%EC%BB%B4%EC%9A%B46%EC%A3%BC%EC%B0%A8CH14CH15-%EA%B0%80%EC%83%81-%EB%A9%94%EB%AA%A8%EB%A6%AC-%ED%8C%8C%EC%9D%BC-%EC%8B%9C%EC%8A%A4%ED%85%9C</link>
            <guid>https://velog.io/@flower-in-eyes/%ED%98%BC%EA%B3%B5%EC%BB%B4%EC%9A%B46%EC%A3%BC%EC%B0%A8CH14CH15-%EA%B0%80%EC%83%81-%EB%A9%94%EB%AA%A8%EB%A6%AC-%ED%8C%8C%EC%9D%BC-%EC%8B%9C%EC%8A%A4%ED%85%9C</guid>
            <pubDate>Sun, 23 Feb 2025 17:04:25 GMT</pubDate>
            <description><![CDATA[<h2 id="ch14-가상-메모리brbrbrbr">CH14 가상 메모리<br><br><br><br></h2>
<h3 id="14-1-연속-메모리-할당brbr">14-1 연속 메모리 할당<br><br></h3>
<h4 id="스와핑-swappingbrbr">스와핑 swapping<br><br></h4>
<p>실행 중이지 않은 프로세스를 보조기억장치로 옮겨 놓았다가 필요할때 다시 불러오는 동작을 스와핑이라고 함.<br><br></p>
<p>swap-out: 현재 필요없는 프로세스가 보조기억장치로 가는거<br><br></p>
<p>swap-in: 다시 메모리로 돌아오는거<br><br></p>
<h4 id="메모리-할당-memory-allocationbrbr">메모리 할당 memory allocation<br><br></h4>
<ol>
<li>최초 적합 first fit: 할당 가능한 빈공간을 최초로 발견한 곳에 할당</li>
<li>최적 적합 best fit: 메모리를 전부 탐색하며 할당 가능한 공간 중 가장 작은 곳에 딱 맞게 할당</li>
<li>최악 적합 worst fit: 메모리를 전부 탐색하고 할당 가능한 공산 중 가장 큰 곳에 쓸데 없이 할당<br><br></li>
</ol>
<h4 id="단편화-fragmentationbrbr">단편화 fragmentation<br><br></h4>
<p>정의: 여러 개의 조각으로 나뉘는 현상. 대상은 일반적으로 공간 혹은 자료이다.<br><br></p>
<h5 id="외부-단편화-external-fragmentationbrbr">외부 단편화 external fragmentation<br><br></h5>
<p>커다란 메모리가 프로세스의 스와핑 결과 중간 중간 뻥뻥 뚫리게 된다. 이는 아무리 큰 메모리라 하더라도 결국 이전에 할당 된 크기 만큼의 메모리 여러개로 나눠 진거나 마찬가지다.<br><br></p>
<p>외부라는 의미는 프로세스 밖에 단편화된 메모리 조각들이 생기기에 외부 단편화라고 한다<br><br></p>
<h5 id="내부-단편화-internal-fragmentationbrbr">내부 단편화 internal fragmentation<br><br></h5>
<p>프로세스에 필요한 메모리 조각은 운영체제가 관리하는 최소 단위의 배수로 딱딱 떨어지지 않을 수 있다. 그럴 경우 운영체제가 할당하는 블록 내부에 빈공간이 생길 수 밖에 없는데 이는 곧 메모리의 단편화라고 할 수 있다.<br><br></p>
<p>프로세스의 내부에 생기기에 내부 단편화라고 한다. 당연히 앞서 본 외부 단편화의 크기 보다는 훨씬 작을 수 밖에 없긴하다<br><br></p>
<h4 id="연속할당에서-단편화-문제brbr">연속할당에서 단편화 문제<br><br></h4>
<p>특히 외부 단편화에 있어 치명적이다.<br><br></p>
<p>왜냐하면, 프로세스가 한 뭉태기로 메모리에 실려 있어야 되는데, 스와핑의 결과 불가능한 단위 크기만큼 무수히 많은 외부 단편화가 일어나 있다면, 그 공간을 전부 다 못쓰게 되기 때문이다.<br><br></p>
<p>이를 극복하기 위해 페이징 개념이 등장하게 된다. 혹은 외부 단편화를 해결하기위해 적재된 프로세스들을 차곡히 정렬하는 메모리 압축<code>memory compaction</code> 도 방법이지만, 주소를 하나하나 옮기는 과정에서 무수히 많은 오버헤드가 발생하고 스와핑이 일어날때마다 해줘야되면 감당이 안됨<br><br></p>
<h4 id="확인-문제brbr">확인 문제<br><br></h4>
<p>1️⃣ 메모리 할당 방식에 대한 설명으로 올바른 것 매칭<br><br></p>
<ul>
<li>최초로 발견한 적재 가능한 빈 공간에 프로세스 배치: ( )</li>
<li>프로세스가 적재될 수 잇는 가장 큰 공간에 프로세스 배치: ( )</li>
<li>프로세스가 적재될 수 있는 가장 작은 공간에 프로세스 배치:( )</li>
</ul>
<details>
  <summary> 더 보기 </summary>
  <div>최초 적합, 최악 적합, 최적 적합</div>
</details><br><br>

<p>2️⃣ 외부 단편화 설명 옳지 않은 것<br><br></p>
<ol>
<li>외부 단편화가 발생하면 메모리가 낭비됨</li>
<li>가상 메모리 기법 주 페이징을 사용하면 외부 단편화 해결 가능</li>
<li>메모리 압축을 통해 외부 단편화를 해결할 수 있음</li>
<li>외부 단편화가 발생한 공간에 모든 프로세스 배치할 수 있음</li>
</ol>
<details>
  <summary> 더 보기 </summary>
  <div>4번 외부 단편화가 발생하면 배치 할 수 없는 프로세스들이 발생할 수 있음. 연속할당이라면</div>
</details><br><br>

<p>3️⃣ 메모리 스와핑에 대한 설명으로 옳은 것은?<br><br></p>
<ol>
<li>메모리에서 보조기억장치로 가는게 스왑 인</li>
<li>보조기억장치에서 메모리로 오는게 스왑 아웃</li>
<li>CPU 관리 기법</li>
<li>메모리에서 사용되지 않는 일부 프로세스를 보조기억장치로 내보내고 실행할 프로세스는 메모리에 적재하는 기법</li>
</ol>
<details>
  <summary> 더 보기 </summary>
  <div>4번 그냥 정의</div>
</details><br><br>


<p>4️⃣ 연속 메모리 할당에 대한 설명 중 옳지 않은것<br><br></p>
<ol>
<li>외부 단편화가 발생하지 않는다</li>
<li>프로세스를 메모리에 연속적으로 할당한다</li>
<li>메모리 스와핑을 이용할 수 있다</li>
<li>최초 적합, 최적 적합, 최악 적합으로 프로세스를 적재할 수 있다.</li>
</ol>
<details>
  <summary> 더 보기 </summary>
  <div> 1번. 스와핑이 일어난다는 조건이면 외부 단편화가 일어나는거고, 이때 연속할당 시스템이면 특히 외부 단편화에 취약하다.</div>
</details><br><br>

<h3 id="14-2-페이징을-통한-가상-메모리-관리brbr">14-2 페이징을 통한 가상 메모리 관리<br><br></h3>
<h4 id="페이징-프레임brbr">페이징, 프레임<br><br></h4>
<p>페이징 paging: 프로세스의 근본은 연속된 논리 주소를 가져야 한다. 그러나 이렇게 되면 너무 나도 좋겠지만, 현실적으로 메모리 외부 단편화에 너무 취약하기 때문에 연속된 공간이 아닌 분산된 공간에 저장하더라도 마치 연속으로 저장되어 있는 거 마냥 사용 할 수 있다면 좋을거 같아서 만들어진 개념이 페이징<br><br></p>
<p>프레임 frame: 논리주소는 그렇다치고 실제 물리 주소가 있을거 아닌가. 이때 메모리를 관리하는 운영체제 및 하드웨어 입장에서 유동적으로 1byte 단위까지 유연하게 처리할 수 있게 해버리면 설계가 너무 어려워진다. 그래서 설계 용이한 단위로다가 메모리를 나눈것이다. 메모리의 총 공간을 일정 크기 단위로 나눌때 그 단위가 프레임이다.<br><br></p>
<h4 id="페이지-인-페이지-아웃-내부-단편화brbr">페이지 인, 페이지 아웃, 내부 단편화<br><br></h4>
<p>페이지 인: 스왑 인이 프로세스 통짜로 메모리에 적재하는 거면, 페이지 인은 그 바라보면 대상이 페이지로 바뀐 것이다.<br><br></p>
<p>페이지 아웃: 사용 안하는 페이지는 보조기억장치로 옮겨지는 현상<br><br></p>
<p>내부 단편화: 프레임으로 메모리를 관리하는 개념이 도입되는 순간, 사용하지 못하는 공간이 발생하게 된다. 땅을 일정 건물로 다 나눠놓았는데 누구는 그 공간을 다 쓰고 누구는 그 공간을 낭비할 수도 있는 거다. 그런 개념이 발생할 수 밖에 없다, 원인은 프레임<br><br></p>
<h4 id="페이지-테이블brbr">페이지 테이블<br><br></h4>
<p>페이지를 분산된 프레임 속에 적절하게 배치한다고 할때 CPU 입장에서는 당황스럽다. 명령어 자체는 그냥 바로 다음 주소인데 실제 논리주소와 물리 주소간 차이 발생하기 때문이다. 이 모든걸 해결해 주는게 페이지 테이블이다.<br><br></p>
<p>논리 주소에 매칭되어 실제 프레임 주소를 반환해주는 테이블을 이용해 오류 없이 계산한다.<br><br></p>
<p>각 프로세스 마다 페이지 테이블이 존재하고, 이 페이지 테이블은 메모리에 따로 적재되어 있으며, 해당 페이지 테이블의 주소는 CPU의 레지스터에 저장되어 있는데 그게 바로 <code>페이지 테이블 베이스 레지스터</code> <code>PTBR; Page Table Base Register</code>이다. 레지스터에 주소를 올려 놓은 것만으로도 메모리에 연속적으로 접근해야되는 수고를 덜어준다.<br><br></p>
<p>그런데 이렇게 주소만 가지고 있어도 어차피 메모리를 한 번 이상 접근해야되는건 똑같다. 그래서 이를 극복하기 위해 MMU 안에 <code>TLB; Translation Lookaside Buffer</code>라는 캐시메모리를 두어 메모리 접근 없이도 바로 메모리 주소 참조할 수 있게하는 방식으로 성능을 향상시킨다.<br><br></p>
<h4 id="페이징-주소-변환brbr">페이징 주소 변환<br><br></h4>
<p>핵심은. 명령어는 결국 페이지+ 변위이다.<br><br></p>
<p>더 구체적으로 만약 페이지의 단위가 4096이라 했을때, 논리주소 10000은 4096으로 나누면 페이지 번호이다. 그리고 논리주소를 4096으로 나눈 나머지가 변위가 되게 된다. 이게 페이지번호와 변위로 이루어져 있다는 의미이다.<br><br></p>
<p>페이지 번호로 찾아간 뒤 변위를 더해 필요한 주소값에 접근한다. 이때 페이지 번호와 매칭되는 값은 프레임 번호이고, 그것이 저장된 테이블이 페이지 테이블임.<br><br></p>
<h4 id="페이지-테이블-엔트리brbr">페이지 테이블 엔트리<br><br></h4>
<p>페이지 테이블 한 행 한 행을 페이지 테이블 엔트리라고 한다.
페이지 테이블 엔트리의 핵심은 페이지 주소를 실제 프레임주소로 매칭시키는것. 그 외 여러 정보들이 저장되어 있다. <code>유효 비트</code> <code>부호 비트</code> <code>참조 비트</code> <code>수정 비트</code> <br><br></p>
<h5 id="유효-비트-valid-bitbrbr">유효 비트 valid bit<br><br></h5>
<p>페이지도 스와핑을 한다. 막 실행중인 프로세스라고 하더라도, 페이지 단위로 페이지 아웃이 되어 있을 수 있다. 페이지 아웃이 일어나 잇는 상태면 유효비트 == 0, 페이지 인 되어 있는 상태면 유효 비트 == 1<br><br></p>
<p>존재 이유: 메모리에 없으면 참조 명령어가 일어날 때 페이지 폴트 예외를 발생시키고  폴트 처리 루틴을 수행한 뒤에 돌아와서 에러 없게 한다.<br><br></p>
<h5 id="보호-비트-protection-bitbrbr">보호 비트 protection bit<br><br></h5>
<p>이진 보호 비트 : 읽기만 가능한 상태면 0 쓰기도 가능한 상태면 1<br><br></p>
<p> 복잡한 보호 비트: r, w, x 등의 구체적인 보호 비트를 두고서 true면 1 false면 0을 두는 방식<br><br></p>
<p> 존재 이유: 보호 비트가 없는 채로 읽기 쓰기 명령이 막 일어나면 데이터 무결성을 해친다.<br><br></p>
<h5 id="참조-비트-reference-bitbrbr">참조 비트 reference bit<br><br></h5>
<p>cpu가 참조한 적있는지 아직 사용안했는지를 구별하는 비트<br><br></p>
<p>존재 이유: 페이지 교체 알고리즘에서 사용됨. <code>LRU; Least Recently Used</code> 페이지 교체 알고리즘은 참조비트 값을 비교하여 어떤 녀석을 페이지 아웃 시킬지 결정하기 때문<br><br></p>
<h5 id="수정-비트-modified-bitbrbr">수정 비트 modified bit<br><br></h5>
<p>변경된 적이 있는지 없는지를 구별하는 비트<br><br></p>
<p>존재 이유: 디스크 저장 하드웨어 사용 자원 효율 향상에 필요함. 한번도 수정된 적이 없는 페이지는 디스크에 저장할 필요가 없기에 그냥 날려버리면 됨.<br><br></p>
<h4 id="확인문제-brbr">확인문제 <br><br></h4>
<p>1️⃣ 페이징에 대한 설명으로 옳지 않은 것을 골라보세요.<br><br></p>
<ol>
<li>페이징은 가상 메모리 관리 기법</li>
<li>페이징을 이용하면 물리 메모리보다 큰 프로세스도 실행 할 수 있음</li>
<li>PTBR은 각 프로세스가 적재된 페이지 테이블을 가리킵니다.</li>
<li>TLB 히트가 발생하면 CPU는 메모리에 두 번 접근해야한다.</li>
</ol>
<details>
  <summary> 더 보기 </summary>
  <div> 4. 반대이다. TLB 히트가 메모리에서 TLB에 가져올 필요가 없는 거다.</div>
</details><br><br>

<p>2️⃣ 3️⃣ 4️⃣</p>
<h2 id="ch15-파일-시스템brbr">CH15 파일 시스템<br><br></h2>
]]></description>
        </item>
        <item>
            <title><![CDATA[혼공컴운_7주차_혼공스터디_참여_회고]]></title>
            <link>https://velog.io/@flower-in-eyes/%ED%98%BC%EA%B3%B5%EC%BB%B4%EC%9A%B47%EC%A3%BC%EC%B0%A8%ED%98%BC%EA%B3%B5%EC%8A%A4%ED%84%B0%EB%94%94%EC%B0%B8%EC%97%AC%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@flower-in-eyes/%ED%98%BC%EA%B3%B5%EC%BB%B4%EC%9A%B47%EC%A3%BC%EC%B0%A8%ED%98%BC%EA%B3%B5%EC%8A%A4%ED%84%B0%EB%94%94%EC%B0%B8%EC%97%AC%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Sun, 23 Feb 2025 17:00:45 GMT</pubDate>
            <description><![CDATA[<h2 id="드는-생각brbr">드는 생각<br><br></h2>
<h3 id="끝이-없다brbr">끝이 없다<br><br></h3>
<p>시간은 부족하고, 머리는 제대로 돌아가지 않으며, 마음은 조급하고, 몸은 지쳐간다.<br><br></p>
<h3 id="대단한-사람이-되고-있다brbr">대단한 사람이 되고 있다<br><br></h3>
<p>그럼에도 불구하고 배움이 남는다는 것. 더 나은 사람이 되어가고 있다.  <br><br></p>
<p>이제는 재미를 느끼지 못할 때도 있다. 하지만 재미를 넘어서, 새로운 감각 속에서 몰랐던 개념을 이해하고 답할 수 있게 되었다는 자부심이 생긴다.<br><br></p>
<h3 id="감사합니다brbr">감사합니다.<br><br></h3>
<h4 id="혼공족장님brbr">혼공족장님<br><br></h4>
<p>항상 격려해 주시는 혼공족장님께 감사드립니다.<br><br></p>
<h4 id="한빛출판네트워크brbr">한빛출판네트워크<br><br></h4>
<p>좋은 책을 만들어 주신 저자님과 출판사에 감사드립니다. 더 많은 책이 전자책으로 제공되길 바랍니다.  특히, 참고하기 좋은 이론 관련 도서들이 구글 E-Book 플랫폼에 없는 점이 아쉬웠습니다. <br><br></p>
<p>하지만 좋은 기획과 스터디 기회를 주셔서 정말 감사드립니다. 많은 힘이 됩니다.  이런 기획은 한빛 혼공 시리즈만이 할 수 있는 것 같습니다. 개발 도서는 역시 한빛이 최고입니다.<br><br></p>
<h4 id="강민철-저자님-방송대-김진욱-교수님brbr">강민철 저자님, 방송대 김진욱 교수님<br><br></h4>
<p>좋은 구성의 책을 써주신 강민철 저자님께 감사드립니다. 덕분에 자격증 시험을 위해 기계적으로 외웠던 개념을 넘어서,  진짜 운영체제의 핵심 개념을 이해하는 기회를 얻었습니다.<br><br></p>
<p>또한, 공부하면서 스스로 이해하기 어려웠던 부분들을 명쾌하게 설명해 주신 방송대 컴퓨터과학과 김진욱 교수님께도 진심으로 감사드립니다.  저도 언젠가 누군가에게 답을 줄 수 있는 사람이 되고 싶다고 더욱더 느낍니다.<br><br></p>
<h4 id="동료분들brbr">동료분들<br><br></h4>
<p>직접 만나본 적은 없지만, 같은 길을 걸으며 공부하는 여러분께도 감사합니다.  여러분의 노력과 열정이 저에게도 큰 동기부여가 되고, 좋은 참고가 됩니다. 응원합니다.<br><br></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[혼공컴운_5주차_CH12_CH13_프로세스 동기화, 교착 상태]]></title>
            <link>https://velog.io/@flower-in-eyes/%ED%98%BC%EA%B3%B5%EC%BB%B4%EC%9A%B45%EC%A3%BC%EC%B0%A8CH12CH13%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4-%EB%8F%99%EA%B8%B0%ED%99%94-%EA%B5%90%EC%B0%A9-%EC%83%81%ED%83%9C</link>
            <guid>https://velog.io/@flower-in-eyes/%ED%98%BC%EA%B3%B5%EC%BB%B4%EC%9A%B45%EC%A3%BC%EC%B0%A8CH12CH13%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4-%EB%8F%99%EA%B8%B0%ED%99%94-%EA%B5%90%EC%B0%A9-%EC%83%81%ED%83%9C</guid>
            <pubDate>Tue, 18 Feb 2025 12:14:01 GMT</pubDate>
            <description><![CDATA[<h2 id="ch12-프로세스-동기화brbr">CH12 프로세스 동기화<br><br></h2>
<h3 id="12-1-동기화란brbr">12-1 동기화란<br><br></h3>
<p>정의: 시스템을 동시에 작동시키기 위해 사건들을 조화시키는 것<br><br></p>
<p>여러 도메인에 걸쳐 상당히 자주 등장하는 개념이다.<br><br></p>
<p>현재 도메인은 프로세스.<br><br></p>
<p>프로세스의 동기화 정의: 여러 다른 프로세스들 간 사이의 동작을 올바르게 맞추기 위한 여러 방법<br><br></p>
<p>스레드의 동기화: 한 프로세스 내에 여러 스레드들 사이의 동작을 올바르게 맞추는 것<br><br></p>
<p>프로세스 동기화를 통해서 하려는 일: 실행 순서 제어, 상호 배제<br><br></p>
<p>실행 순서 제어: 프로세스가 동시에 실행되는 것 처럼 보이게끔 스케쥴링하는 것.<br><br></p>
<p>상호 배제: 이때 동시에 접근해서는 안되는 자원에는 접근 제한을 거는 것<br><br></p>
<p>결국 동시에 여러 프로세스를 굴리기 위해서는 &lt;- 실행 순서 제어와 상호 배제를 구현해야하고 &lt;- 그것들을 구현하는 방법이 == 프로세스 동기화 &lt;- 그리고 그 동기화의 방법으로는 뮤텍스, 세마포어, 모니터 등이 있는 것.<br><br></p>
<h4 id="생산자-소비자-문제에서-공유-자원과-임계-구역brbr">생산자 소비자 문제에서 공유 자원과 임계 구역<br><br></h4>
<p>총합이란 변수가 존재하고, 소비하다() 함수는 1을 빼고 총합을 갱신, 생상하다() 함수는 1을 더하고 총합을 갱신하는 간단한 로직이 있다 할때, <code>공유자원</code>을 건드리는 <code>임계구역</code>이라는 개념을 가지고 있지 않으면 똑같이 반복문 100번 돌려 놓으면  총합은 10일거라고 착각 하게 된다. but 결과는 천차만별이다.<br><br></p>
<p>생산하다 소비하다를 각각 호출할때 아직 총합의 갱신이 이루어지지 않은채로 막 지가 알아서 지 멋대로 값을 갱신을 하다보면 마이너스까지 내려가기도, 혹은 +100 온전히 다 받아들일 수도 있기 때문이다.<br><br></p>
<p>공유자원은 이렇게 공동으로 사용하는 총합 같은 것이 공유 자원이고, 임계구역은 이런 공유자원을 건드리는 코드 영역을 임계구역이라고 함.<br><br></p>
<p>이런 경우 흔히 상호 배제를 구현하여 해결한다. 
상호 배제 mutual exclusion: 어떤 프로세스가 임계구역을 실행중일땐 다른 모든 프로세스는 임계구역을 실행할 수 없다.
진행 progress:  임계구역을 아무도 실행중이지 않다면 프로세스는 진행할 수 있어야 한다.
유한 대기 bounded waiting: 상호 배제는 유한하게 유지되고 언젠가는 진행상태로 올수 있게 해야한다. (설사 앞선 프로세스가 다 마치지 못했다 하더라도 무한대기는 안된다.)<br><br></p>
<h4 id="확인-문제brbr">확인 문제<br><br></h4>
<p>1️⃣ 동기화의 의미에 대한 설명 빈칸 채우기<br><br></p>
<p>(    )를 위한 동기화: 프로세스를 올바른 순서대로 실행하기</p>
<details>
  <summary> 더 보기 </summary>
  <div>실행 순서 제어</div>
</details>

<p>(    )를 위한 동기화: 동시에 접근해서는 안되는 자원에...</p>
<details>
  <summary> 더 보기 </summary>
  <div> 상호 배제 </div>
</details>

<p>2️⃣ 임계 구역에 대한 설명 중 옳지 않은 것<br><br></p>
<ol>
<li>임계 구역에서 여러 프로세스 동시 실행 무방</li>
<li>임계 구역에서 여러 프로세스 동시에 실행할 경우 레이스 컨디션 발생</li>
<li>임계 구역에서 실행중인 프로세스 있다면, 다른 프로세스 기다림</li>
<li>운영체제는 임계 구역 관리</li>
</ol>
<details>
  <summary> 더 보기 </summary>
  <div>1번 임계 구역일 수록 여러 프로세스 동시 실행 위험</div>
</details>

<p><br><br></p>
<h3 id="12-2-동기화-기법brbr">12-2 동기화 기법<br><br></h3>
<h4 id="뮤텍스-락-mutex-lock-mutual-exclusion-lockbrbr">뮤텍스 락 Mutex lock: Mutual Exclusion lock<br><br></h4>
<p>직역하면 그냥 이게 <code>상호배재락</code> 기법이다.<br><br></p>
<p>lock변수, acquire(), release() 총 세 개의 핵심 동작으로 상호배재락을 구현<br><br></p>
<pre><code>// mutual exclusion lock의 간단한 구성 조건
...
static boolean lock = false;
...
static void acquire(){
    while(lock==true){
        //대기
    }
    lock = true; //종료
}
static void release(){
    lock= false;
}

...
//공유 자원을 사용하고 자 하는 매서드: acquire와 release()로 감싸는게 포인트
acquire(); //lock을 얻은 프로세스만 탈출
useSharedResource();//임계구역 사용하는 코드
release(); //임계구역을 성공적으로 사용했다면 lock=false로 반납
...</code></pre><p><br><br></p>
<h4 id="세마포-semaphorebrbr">세마포 semaphore<br><br></h4>
<p><a href="https://en.dict.naver.com/#/entry/enko/"><strong>sema·phore</strong></a>
1.수기 신호 2.수기 신호로 알리다<br><br></p>
<p>결국 임계구역을 동시에 접근하는 것을 막기 위한 하나의 수단이고 이 방법은 <code>뮤텍스락</code>과 크게 다르지 않지만, 몇가지 유의미한 차이가 있다.<br><br></p>
<p>그 전에 세마포를 이루는 개념 3가지. count변수(S변수), wait, signal<br><br></p>
<p>count : 동시에 접근 가능한 프로세스를 몇 개를 둘 지를 결정한다. 최소 값은 0 최대 값은 설정값이다. 만약 1이라면 뮤텍스락과 유사한, 동시에 한 작업만 가능한 자원으로 상호배제를 만족하게 되는거고, 2이상이라면 여러 작업이 사용해도 되는 자원이라는 의미<br><br></p>
<p>세마포에 대하여 구체적인 내용은 Operating Systems Concepts라는 심도 있는 책을 통해 보강할 예정이다. 현 책에 있는 내용으로는 의문점을 해결하지 못하였다.<br><br></p>
<h4 id="모니터-monitorbrbr">모니터 monitor<br><br></h4>
<p>동기화 툴의 향상된 개념이다. 공유자원을 사용하는 모든 연산에 인터페이스를 묶어서 관리한다. 공유자원 사용을 위한 대기 큐에 넣어놓고, 사용 할 수 있는 조건이 되었을때 poll하여 공유자원 상호배제를 수행함.<br><br></p>
<p>모니터 역시 나중에 더 심화를 다뤄야 겠다. 부족하다 소스가<br><br></p>
<h4 id="확인-문제brbr-1">확인 문제<br><br></h4>
<p>1️⃣ 뮤텍스 락과 세마포에 대한 설명으로 옳지 않은 것<br><br></p>
<ol>
<li>뮤텍스락은 임계 구역을 잠근 뒤 진입. 상호 배제를 위한 동기화</li>
<li>세마포는 공유 자원이 여러 개 있는 상황에서도 이용 가능</li>
<li>세마포를 이용해 프로세스 실행 순서 제어를 위한 동기화 가능</li>
<li>세마포를 이용하면 반드시 바쁜 대기를 해야 한다.</li>
</ol>
<details>
  <summary> 더 보기 </summary>
  <div>4번 바쁜대기는 뮤텍스락의 특징</div>
</details>


<p>2️⃣ 조건 변수 x와 y가 있다. 스레드 A는 실행 과정에서 x.wait을 호출. 스레드 B는 y.wait을 호출. 스레드 C가 y.signal을 호출하면 재개되는 스레드 명은?</p>
<details>
  <summary> 더 보기 </summary>
  <div>스레드 B</div>
</details>

<p>3️⃣ 빈칸에 들어갈 말<br><br></p>
<p>세마포를 이용하면 동시에 실행되는 프로세스 혹은 스레드 간에 ()를 위한 동기화와 ()를 위한 동기화를 할 수 있다.</p>
<details>
  <summary> 더 보기 </summary>
  <div>실행 순서 제어, 상호 배제</div>
</details>

<p><br><br></p>
<h2 id="ch-13-교착-상태--deadlockbrbr">CH 13 교착 상태 : deadlock<br><br></h2>
<h3 id="13-1-교착-상태란brbr">13-1 교착 상태란<br><br></h3>
<p>공용자원과 프로세스가 있을때 프로세스A를 수행하기 위해 공용자원 A, B가 필요하고 프로세스B를 수행하기 위해 공용자원 A,B가 필요할때 각각 하나씩 나누어서 집어들은 상태에서 무한 대기 상태가 걸려 아무것도 못하는 상태가 교착 상태.<br><br></p>
<h4 id="교착-상태-발생-조건brbr">교착 상태 발생 조건<br><br></h4>
<p>아래 4가지 중 하나라도 조건에서 해제 된다면 교착 상태를 풀 수 있다.<br><br></p>
<ol start="5">
<li>상호 배제:  공유 자원 동시에 사용 못하게</li>
<li>점유와 대기: 자원을 점유한 채 할당 받을때까지 대기 하는 방식</li>
<li>비선점: 다른 프로세스가 아직 자원을 사용중이라면, 자원을 뺐을 수 없게 함.</li>
<li>원형 대기: 결국 최악의 경우는 수천 개의 스레드 및 수백개의 스레드가 일말의 예외 없이 전부 자원 대기 상태에 걸린 원형 대기 상태라면 교착은 무조건 발생.<br><br></li>
</ol>
<h4 id="확인-문제brbr-2">확인 문제<br><br></h4>
<p>1️⃣ 교착 상태에 대한 설명으로 옳지 않은 것?<br><br></p>
<ol>
<li>교착 상태는 다양한 상황에서 발생</li>
<li>교착 상태는 자원 할당 그래프로 표현 가능</li>
<li>교착 상태는 일어나지 않을 사건 기다리며 무한히 대기하는 현상</li>
<li>식사하는 철학자 문제에서 단 한 명의 철학자가 식사를 하더라도 교착 상태는 발생</li>
</ol>
<details>
  <summary> 더 보기 </summary>
  <div>4번 한명만 먹는거는 교착 상태 발생 X</div>
</details>
<br><br>

<p>2️⃣ 교착 상태 발생 조건 4가지 서술</p>
<details>
  <summary> 더 보기 </summary>
  <div>원형대기, 선점과 대기, 상호배제, 비선점</div>
</details>
<br><br>

<p>3️⃣ 교착 상태가 발생할 위험이 있는 그래프의 특징</p>
<details>
  <summary> 더 보기 </summary>
  <div>사이클을 그리는 형태</div>
</details>
<br><br>

<h3 id="13-2-교착-상태-해결-방법brbr">13-2 교착 상태 해결 방법<br><br></h3>
<h4 id="예방-preventionbrbr">예방 prevention<br><br></h4>
<ol>
<li><p>상호 배제: 동기화 방법을 통해 기껏 만든 상호 배제 때문에 교착 상태가 발생될 수 있다면, 그냥 애라 모르겠다. 아무렇게나 자원 동시에 막쓰게 풀어버리자. 그럼 교착 상태는 해방가능<br><br></p>
</li>
<li><p>점유와 대기: 프로세스를 진행할때 자원을 점유하고 나머지 자원이 도착할때까지 기다리는 상황이 점유와 대기인데, 점유와 대기를 하지 않게끔. 즉 프로세스가 자원을 사용할때 온전히 사용하게 하는 형태. 이렇게 되면 문제가 프로세스를 잘게 쪼개어 여러 프로세스가 동시에 동작하게끔 하는게 안된다. 점유와 대기가 안일어나면 즉 효율은 떨어진다. 또 자원 이용시간이 길어질 경우 자원 점유후 바로 해제해야하므로 영영 굶는 기아 상태에 빠질 수 있음<br><br></p>
</li>
<li><p>비선점: 선점을 아무나 막 할 수 있게 해버리면 크리티컬한 문제가 발생 할 수 있다. 예를들어 프린터기가 있을 수 있다. 프린터기 자원이 필요한 프로세스가 자신의 작업을 막 수행하려 할때마다 선점해서 사용해버리니 이상한 출력물이 나올 가능성이 매우 높다.<br><br></p>
</li>
<li><p>원형대기: 현실적인 <code>예방</code>방법이다. 순환이 발생하는 구조를 차단시켜버린다. -&gt; 즉 시작과 끝의 값을 매겨서 항상 번호가 앞순위의 자원만 추가로 대기할 수 있게 혹은 후순위의 자원만 추가로 대기할 수 있게 설정하는 방법</p>
<ol>
<li>문제는 그 방법 자체가 굉장히 비효율적이다. 모든 자원에 번호를 매긴다는 점 자체가 비효율적. 번호를 매기지 않으면 끝과 끝을 구별할 수 없기 때문.<br><br></li>
</ol>
</li>
</ol>
<p>결국 prevention은 해결 방법중에서 가장 비효율적인 해결 방법이다.<br><br></p>
<h4 id="회피-avoidancebrbr">회피 avoidance<br><br></h4>
<p>교착 상태의 원흉: 한정된 자원 + 너무 많은 프로세스가 동시에 사용하려고 함.<br><br></p>
<p>회피: 프로세스들이 아무리 많아지더라도 한정된 자원을 안전하게 제공하자 -&gt; 조심히 교착 상태에 빠지지 않게, 그러면서 동시에 최대한 효율적이고 균등하게 배분할 수 있도록 하자 -&gt; 프로세스 요구 자원량에 대한 계산이 미리 필요<br><br></p>
<p>프로세스는 나는 어느정도 자원을 사용할거에요 미리 알려줘야하고,
운영체제는 프로세스가 표시한 자원량을 스캔하여 현재 스케쥴링된 프로세스들을 어떻게 관리하여 실행시킬지 데드락이 안걸리게 할지 생각을 해야함.<br><br></p>
<p>프로세스의 최대 자원 사용량 정보가 저장되는 장소: 운영체제 리소스 매니저
해당 정보들을 이용하여 데드락 회피 알고리즘을 계산 하는 주체: 운영체제 리소스 매니저
회피 알고리즘의 결과를 토대로 프로세스 스케쥴링을 결정하는 주체: 운영체제 스케쥴러<br><br></p>
<p>회피만으로 백프로 데드락을 방지 할 수 있는가? -&gt; NO 왜냐하면, 사용량 정보보다 실제 사용량이 더 많아지는 경우 자체가 있을 수 있으며, 빡빡한 자원속에서 데드락 조건이 발생할 가능성은 충분히 있음<br><br></p>
<p>결국 회복 알고리즘으로 극복을 해야만 함.<br><br></p>
<h4 id="탐지-및-회복-detection-and-recoverybrbr">탐지 및 회복 detection and recovery<br><br></h4>
<p>일단 탐지 알고리즘에 대한 내용은 고급과정이라서 설명을 안하고 넘어간다<br><br></p>
<ol>
<li>프로세스 강제 종료</li>
<li>자원 선점</li>
</ol>
<p>2가지 방식으로 교착 상태를 회복한다. 물론 현재 내용을 복구 하기 위한 체크포인트 개념도 있다고 하는데 설명하지 않고 넘어간다<br><br></p>
<h4 id="확인-문제brbr-3">확인 문제<br><br></h4>
<p>1️⃣ 교착 상태를 회복하는 방법 틀린거<br><br></p>
<ol>
<li>교착 상태 조건 중 하나를 충족하지 않게 하면 예방 가능</li>
<li>교착 상태는 회복 할 수 없다</li>
<li>안전 상태를 유지할 수 있는 경우에만 자원을 할당하면 교착 회피 가능</li>
<li>교착 상태 검출 및 회피 방식에서 주기적으로 교착 발생 여부를 검사</li>
</ol>
<details>
  <summary> 더 보기 </summary>
  <div> 2번 회복의 방법이 있다. </div>
</details><br><br>

<p>2️⃣ 아래 표 상태에서 P2에 자원 2개 나누어 줬다.  프로세스 P2가 실행 올바르게 종료한뒤 자원 반납 하면 남은자원은?<br><br></p>
<table>
<thead>
<tr>
<th align="left">프로세스</th>
<th align="left">요구량</th>
<th align="left">현재 사용량</th>
</tr>
</thead>
<tbody><tr>
<td align="left">P1</td>
<td align="left">10</td>
<td align="left">5</td>
</tr>
<tr>
<td align="left">P2</td>
<td align="left">4</td>
<td align="left">2</td>
</tr>
<tr>
<td align="left">P3</td>
<td align="left">9</td>
<td align="left">2</td>
</tr>
<tr>
<td align="left">- 할당 가능 자원 12</td>
<td align="left"></td>
<td align="left"></td>
</tr>
<tr>
<td align="left">- 할당한 자원 총합 현재 9</td>
<td align="left"></td>
<td align="left"></td>
</tr>
<tr>
<td align="left">- 남은 자원 3</td>
<td align="left"></td>
<td align="left"></td>
</tr>
</tbody></table>
<details>
  <summary> 더 보기 </summary>
  <div>남은 자원 = 할당 가능 자원 - 할당한 자원 = 12 - 7 = 5</div>
</details><br><br>

<p>3️⃣ 교착 상태에 대한 대처 방법 중 타조 알고리즘 설명<br><br></p>
<details>
  <summary> 더 보기 </summary>
  <div>교착 상태를 무시한다</div>
</details><br><br>

<p>4️⃣ 교착 상태 예방에 대한 설명으로 옳지 않은 것은?<br><br></p>
<ol>
<li>상호 배제 조건 없애기</li>
<li>점유와 대기 조건 없애기</li>
<li>비선점 조건 없애기</li>
<li>원 형 대기 조건을 추가하기</li>
</ol>
<details>
  <summary> 더 보기 </summary>
  <div>4번 원형 대기 조건 없애야 된다</div>
</details><br><br>]]></description>
        </item>
        <item>
            <title><![CDATA[혼공컴운_4주차_CH09-CH11_운영체제, 프로세스, 스레드, CPU 스케줄링]]></title>
            <link>https://velog.io/@flower-in-eyes/%ED%98%BC%EA%B3%B5%EC%BB%B4%EC%9A%B44%EC%A3%BC%EC%B0%A8CH09-CH11%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C-%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4-%EC%8A%A4%EB%A0%88%EB%93%9C-CPU-%EC%8A%A4%EC%BC%80%EC%A4%84%EB%A7%81</link>
            <guid>https://velog.io/@flower-in-eyes/%ED%98%BC%EA%B3%B5%EC%BB%B4%EC%9A%B44%EC%A3%BC%EC%B0%A8CH09-CH11%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C-%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4-%EC%8A%A4%EB%A0%88%EB%93%9C-CPU-%EC%8A%A4%EC%BC%80%EC%A4%84%EB%A7%81</guid>
            <pubDate>Sat, 08 Feb 2025 09:32:59 GMT</pubDate>
            <description><![CDATA[<h2 id="ch09-운영체제brbr">CH09 운영체제<br><br></h2>
<h3 id="09-1-운영체제를-알아야하는-이유brbr">09-1 운영체제를 알아야하는 이유<br><br></h3>
<h4 id="운영체제란brbr">운영체제란<br><br></h4>
<p>컴퓨터 세상의 정부(=government) 역할을 한다. 인적, 물적 자원들을 행정처리하는것 처럼<br><br></p>
<p>컴퓨터 자원을 컨트롤 타워 역할을 한다.<br><br></p>
<p>물론 기계적으로 보면 명령어를 해석하여 메모리에 올리고, 어떻게 연산하고 하는거는 전부 CPU의 몫이다.<br><br></p>
<p>그런데 말이다. 그 CPU를 다이렉트로 사용자 소프트웨어가 컨트롤해야되는 상황이라고 치자. <br><br></p>
<p>사용자마다 입출력장치의 레지스터 명령어가 다르고, 사용자마다 CPU연산은 다르면 어떻게 컨트롤할건데, 일반 응용프로그램이 대체 얼마나 무거워지고 개발자 죽어난다. <br><br></p>
<p>그래서 컨트롤 타워 역할을 알하서 하는 소프트웨어가 운영체제<br><br></p>
<h4 id="운영체제를-알아야하는-이유brbr">운영체제를 알아야하는 이유<br><br></h4>
<p>컴퓨터 공학을 공부하는 이유... 만능 답안 결국 컴퓨터 세상의 문제해결을 위해서.<br><br></p>
<h4 id="확인문제brbr">확인문제<br><br></h4>
<ol>
<li>시스템 자원</li>
<li>2번</li>
</ol>
<hr>
<h3 id="09-2-운영체제의-큰-그림brbr">09-2 운영체제의 큰 그림<br><br></h3>
<h4 id="커널brbr">커널<br><br></h4>
<p>주기억 장치는 현재 실행중인 모든 프로세스가 다 올라오는 공간이다. <br><br></p>
<p>이는 운영체제에도 예외는 아님. 운영체제도 메모리에 올라와야 비로소 동작하는 것.<br><br></p>
<p>이렇게 운영체제같은 핵심 프로그램은 특수한 공간에 올라오는데 그 특수하게 지정된 공간 <code>커널</code> 영역이다.<br><br></p>
<p>운영체제의 모든 기능들이 다 커널에서 제공되는건 아니다. 커널외 <code>사용자공간</code>에 적재된 기능도 존재하는 데 바로 사용자와 직접 <code>상호작용</code>하기 위한 기능인 <code>UI</code> 기능이다.<br><br></p>
<p>이건 외우는게 아니다. 자연스러운 흐름이다. 사용자가 함부로 건들지 못하게 하기 위해 <code>커널</code>에 적재해야하는 기능이 있는거고, 사용자가 건드려야하는 <code>사용자 영역</code>에 적재헤야되는 기능이 있는것<br><br></p>
<p>UI는 크게 <code>GUI</code> 와 <code>CLI</code> 방식으로 나뉜다. 전자는 그래픽 인터페이스로 마우스나 터치로 클릭하여 반응하는거고, 후자는 커맨드라인이라는 명령어 입력을 직접하여 기능을 동작시키는 인터페이스<br><br></p>
<h4 id="이중-모드와-시스템-호출brbr">이중 모드와 시스템 호출<br><br></h4>
<p>앞서 <code>커널</code>은 사용자의 조작, 응용프로그램의 조작으로부터 안전하게 분리시키기위한 영역이라고 했다. 하지만, 적재만하고 전혀 사용하지 않으면 무슨 소용인가.<br><br></p>
<p>그래서 커널영역안의 코드기능을 사용하고자 할때 시스템 콜을 이용하여 운영체제에게 기능 요청을 하게된다.<br><br></p>
<p>이 때 시스템 호출을 통해 하는 것이 <code>모드 전환</code> 이다. <code>커널 모드</code> 와 <code>사용자 모드</code> 두 가지 모드를 통칭하여 이중 모드라고 하고, 커널모드를 획득해야 비로소 커널 기능을 받아 사용할 수 있게 된다.<br><br></p>
<p>시스템 호출은 인터럽트 방식으로 동작한다. 인터럽트 체크는 새로운 클럭신호에 체크된다. 보내놓고 응답하여 처리하고 다시 돌아오고 방식으로 작동한다는 것.<br><br></p>
<h4 id="운영체제의-서비스brbr">운영체제의 서비스<br><br></h4>
<p>CPU, 메모리, 입출력장치에 이르기까지 사실상 하드웨어를 컨트롤하기 위한 모든 기능은 전부 다 관리한다고 보면 된다. 하드웨어를 관리한다는것 자체가 바로 컴퓨터의 동작이다.<br><br></p>
<h4 id="가상-머신과-이중-모드의-발전brbr">가상 머신과 이중 모드의 발전<br><br></h4>
<p>VM(=Virtual Machine)은 운영체제 위에 또 다른 운영체제 서비스를 구동시키는 것.<br><br></p>
<p>제2의 운영체제도 하드웨어가 있어야 돌아간다. CPU, Memory, 입출력<br><br></p>
<p>이걸 관리하는 놈은 제1의 운영체제이다. <br><br></p>
<p>따라서 제2의 운영체제도 응용프로그램마냥 계속해서 이중모드 컨트롤 인터럽트를 사이클을 반복하며 마치 자기가 컨트롤하고 있는듯이 동작하게 된다.<br><br></p>
<h4 id="시스템-호출의-종류brbr">시스템 호출의 종류<br><br></h4>
<table>
<thead>
<tr>
<th>종류</th>
<th>시스템 호출</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>프로세스 관리</td>
<td>fork()</td>
<td>새 자식 프로세스 생성</td>
</tr>
<tr>
<td></td>
<td>exit()</td>
<td>프로세스 종료</td>
</tr>
<tr>
<td></td>
<td>execve()</td>
<td>프로세스 실행</td>
</tr>
<tr>
<td>----</td>
<td>----</td>
<td>----</td>
</tr>
<tr>
<td>파일 관리</td>
<td>open()</td>
<td>열기</td>
</tr>
<tr>
<td></td>
<td>close()</td>
<td>닫기</td>
</tr>
<tr>
<td></td>
<td>read()</td>
<td>읽기</td>
</tr>
<tr>
<td></td>
<td>write()</td>
<td>쓰기</td>
</tr>
<tr>
<td></td>
<td>stat()</td>
<td>파일 정보 조회</td>
</tr>
<tr>
<td>----</td>
<td>----</td>
<td>----</td>
</tr>
<tr>
<td>디렉터리</td>
<td>mkdir()</td>
<td>메이크 디렉터리</td>
</tr>
<tr>
<td></td>
<td>rmdir()</td>
<td>리무브 디렉터리</td>
</tr>
<tr>
<td>----</td>
<td>----</td>
<td>----</td>
</tr>
<tr>
<td>파일 시스템 관리</td>
<td>mount()</td>
<td>파일 시스템 마운트</td>
</tr>
<tr>
<td></td>
<td>umount()</td>
<td>파일 시스템 언마운트</td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
</tr>
</tbody></table>
<h4 id="확인-문제brbr">확인 문제<br><br></h4>
<ol>
<li>커널</li>
<li>4번</li>
<li>3번은 커널 영역은 아니라서 핵심 서비스가 아니라 하는 것 같다.<br><br></li>
</ol>
<br>

<hr>
<hr>
<br>

<h2 id="ch10-프로세스와-스레드brbr">CH10 프로세스와 스레드<br><br></h2>
<h3 id="10-1-프로세스-개요brbr">10-1 프로세스 개요<br><br></h3>
<h4 id="프로세스brbr">프로세스<br><br></h4>
<p>프로세스: 각자 기능을 맡아 정해진 일을 수행하는 프로그램<br><br></p>
<p>실행중인 프로세스: 메모리 자원을 할당 받고, 각기 다른 사이클로 시스템 자원을 빨아먹어가며 돌아가는 프로세스들<br><br></p>
<p>확인방법: 유닉스는 ps명령어, 윈도우는 작업관리자<br><br></p>
<p>포그라운드 프로세스: foreground process
기능을 수행하는게 현재 관측되는 앞에 나와 기능하는 모든 프로세스<br><br></p>
<p>백그라운드 프로세스: background process
뒤에 숨어서 일을 수행중인 프로세스<br><br></p>
<p>데몬과 서비스: 백그라운드 프로세스 방식 중에서 사용자와 상호작용이 불가능하며, 주어진 상황따라 묵묵히 자기 일을 하는 프로세스<br><br></p>
<h4 id="pcbbrbr">PCB<br><br></h4>
<p>Process Control Block == 프로세스 제어 블록
프로세스와 관련한 정보들이 저장된 데이터 블록이다. 메모리에 적재된다.<br><br></p>
<p>프로세스의 탄생시간이나, 프로세스 아이디값, 프로세스의 메모리 주소, 필요한 입출력장치 등 동적으로 잘 바뀌지 않는 정보들이 프로세스 탄생시에 기입되기도 하지만,<br><br></p>
<p>PCB에는 시시각각 변하는 정보들도 여기에 기입된다. 이는 <code>문맥교환</code>을 위한 필수적인 정보들이며, CPU가 인터럽트를 처리할때, 다른 프로세스들에 잠깐 들렸다가 올때 등등 실행중이던 프로세스가 정상 작동할 수 있게 하는 아주 중요한 핵심 동작 원리이다.<br><br></p>
<p>문맥에 따라 의미가 바뀌는 단어처럼. 프로세스도 현재 상태, 레지스터 값, 사용한 파일 등등 CPU입장에선 문맥이 바뀌고, 프로세스 입장에선 자기 자신 문맥을 보호하기위한 방법이 PCB에 싸그리 저장 때려 박는 방식인것<br><br></p>
<h4 id="context-switchingbrbr">Context Switching<br><br></h4>
<p>문맥교환<br><br></p>
<p>이미 위에 설명을 다 해버렸는데, CPU가 동시에 멀티 프로세스 작업을 하는 것 처럼 보이는 이유는 PCB에 문맥정보를 저장하고, 실시간으로 빠르게 문맥들을 교환해가며 모든 프로세스들을 컨트롤하기 때문이다.<br><br></p>
<p>중요한걸 빼먹었는데 PCB는 핵심적인 기능인 만큼 커널영역에 저장되어 있다. 응용프로그램이 함부로 바꾸지 못하게. 철저하게 운영체제가 관리<br><br></p>
<h4 id="프로세스와-메모리brbr">프로세스와 메모리<br><br></h4>
<p>프로세스는 운영체제와 달리 <code>사용자 영역</code>에 자리 잡는다. 이런 프로세스는 내부적으로 <code>코드영역</code>, <code>데이터 영역</code>, <code>힙 영역</code>, <code>스택 영역</code>으로 나뉜다.<br><br></p>
<p>코드 영역: CPU가 실행할 명령어들의 집합<br><br></p>
<p>데이터 영역: 프로세스부터 사용할 데이터가 미리 적재되어 항시 참조가능한 데이터들의 집합<br><br></p>
<p>힙 영역: 프로그래머에 의해 상황따라 동적으로 변수를 만들고, 데이터를 누적한다면 바로 이 영역에 쌓여 올라간다<br><br></p>
<p>스택 영역: 힙영역과 거꾸로 아래로 누적되어 쌓여가는 구조이다. 동적으로 필요한 데이터들이 생겨나서 push되고 역할끝나면 바로 pop되어서 사라지는 영역. 주로 지금 호출되고 있는 함수의 지역변수, 매개변수, 함수주소 등이 그 예시. 호출되서 반환하면 뭐하겠어? 사라지겠지.<br><br></p>
<p>코드+데이터 = 정적 할당 영역
힙 + 스택 = 동적 할당 영역<br><br></p>
<h4 id="확인-문제brbr-1">확인 문제<br><br></h4>
<ol>
<li>4번</li>
<li>1번</li>
</ol>
<p><br><br></p>
<h3 id="10-2-프로세스-상태와-계층-구조brbr">10-2 프로세스 상태와 계층 구조<br><br></h3>
<h4 id="프로세스-상태brbr">프로세스 상태<br><br></h4>
<p><code>생성상태</code>, <code>준비상태</code>, <code>실행상태</code>, <code>대기상태</code>, <code>종료상태</code><br><br></p>
<p>각각에 대한 설명<br><br></p>
<p>생성상태: 메모리에 올라가고 PCB 작성된 따끈한 상태<br><br></p>
<p>준비상태: CPU 사용준비 완료. 차례가 오길 기다려.<br><br></p>
<p>실행상태: CPU가 받아들여줬어. 열심히 작업을 막해<br><br></p>
<p>대기상태: CPU를 사용할 수 없는 상태. why? 일반적으론 입출력장치 문제인데, 입출력장치의 완료 신호를 기다리는 상태이다<br><br></p>
<p>종료상태: 찐 종료. 이 상태는 오래 있지 않다. 상태전환되자마자 메모리에서 아웃되며, 빠르게 리스트에서 지워짐<br><br></p>
<p>다이어그램
<img src="https://velog.velcdn.com/images/flower-in-eyes/post/36ab5d9e-45ad-41bb-a6de-d8bc14191bc5/image.png" alt="프로세스상태다이어그램"><br><br></p>
<h4 id="프로세스-계층-구조brbr">프로세스 계층 구조<br><br></h4>
<p>프로세스는 그냥 바닥에서 부터 평등하게 시작하는게 아니다. 프로세스를 호출한 녀석이 부모 프로세스가 되어 링크드 리스트 혹은 실제 프로그램의 함수호출 구조 마냥 부모 프로세스 자식 프로세스가 쌓여간다.<br><br></p>
<p>단순한 바탕화면에서 브라우저를 더블클릭하는 거 자체도 운영체제라는 부모 프로세스가 자식프로세스인 브라우저를 생성한거고<br><br></p>
<p>브라우저가 배너를 클릭하니, pc의 소프트웨어 런처가 실행될때에는 브라우저가 부모 프로세스가 되는 형태이다. <br><br></p>
<p>최초의 프로세스가 모두의 부모 프로세스가 되는 경우는 있지만, 최초의 프로세스를 제외한, 다른 모든 프로세스에 부모 프로세스가 없는 경우는 없다.<br><br></p>
<h4 id="프로세스-생성-기법brbr">프로세스 생성 기법<br><br></h4>
<p>결론: 복제와 옷 갈아입기 방식을 사용한다.<br><br></p>
<p>부모 프로세스는 자기 자신을 복제품을 일단 만들고, 이후 자식 프로세스에 필요한 PCB, 코드영역 데이터영역을 채워가며 프로세스를 생성상태를 만들어낸다.<br><br></p>
<p>fork() :복제-&gt; exec(): 덮어쓰기<br><br></p>
<h4 id="확인문제brbr-1">확인문제<br><br></h4>
<ol>
<li>생성상태, 준비상태, 실행상태, 종료상태, 대기상태</li>
<li>로그인 프로세스, vim 프로세스, bash 프로세스</li>
<li>1번</li>
<li>4번<br><br></li>
</ol>
<h3 id="10-3-스레드brbr">10-3 스레드<br><br></h3>
<h4 id="스레드란brbr">스레드란<br><br></h4>
<p>스레드는 어휘적으로 실행의 흐름 단위이다.<br><br></p>
<p>어느 도메인에 걸쳐 있냐에 따라 CPU, 프로그램, 운영체제, 아니면 다른 분야 등등 에서 광범위하게 사용하는 용어임<br><br></p>
<p>여기서는 당연히 프로세스 즉 소프트웨어적인 관점에서의 스레드이다.<br><br></p>
<p>프로세스 내부적으로 만약 하나의 작업만을 한다면 굉자히 어.. 원시적이다. 하지만 지금 어플들의 광범위한 동시다발적 기능을 관찰하자.
지금 에디터에서 글을 쓰는 와중에도 커밋이 발생하고 있으며, 글자 수를 체크하고, 맞춤법을 검사하고 있다.. 이건 다 스레드 덕분인거다. <br><br></p>
<p>왜? 하나의 프로세스를 돌리고 있으니까. 그런데 작업은 여러개를 동시에 처리하고 있으니까.<br><br></p>
<h4 id="멀티프로세스와-멀티스레드-그리고-pcb와-tcbbrbr">멀티프로세스와 멀티스레드 그리고 PCB와 TCB<br><br></h4>
<p>이미 앞서 CPU는 한타이밍에 하나의 작업밖에 못한다고 배웠다. 그 말인 즉슨 동시 작업을 하는것 처럼 보이는 모든 행위는 무수히 빠른 속도로 스위칭하며 모든 프로세스를 한번씩 실행시켜주고 있기 때문이다.<br><br></p>
<p>이는 스레드에서도 같은 원리이다. 문맥교환이 일어나듯이 스레드도 스레드 문맥교환이 일어나고 있는 것이다. <br><br></p>
<p>그러면 PCB같은게 필요하겠네? 
-&gt; 그렇다. PCB같은게 있다. 이를 <code>TCB</code>라고 한다. 
이 TCB는 어디에 있는데? 
-&gt; 커널 영역에 존재하며, 당연히 PCB는 TCB를 링크하기 위한 주소값들을 전부 알고 있는 상태이다.<br><br></p>
<h4 id="확인-문제brbr-2">확인 문제<br><br></h4>
<ol>
<li>2번. 그렇다고 해서 코드 영역 데이터 영역을 무수히 많이 짜개놓을 순 없는 일이다. 공용공간이다. 같은 프로세스라면 말이다.</li>
<li>공유하지 않지만, 공유합니다.<br><br></li>
</ol>
<hr>
<br>

<h2 id="ch11-cpu-스케줄링brbr">CH11 CPU 스케줄링<br><br></h2>
<h3 id="11-1-cpu-스케줄링-개요brbr">11-1 CPU 스케줄링 개요<br><br></h3>
<h4 id="프로세스의-우선순위brbr">프로세스의 우선순위<br><br></h4>
<p>CPU는 프로세스들을 번갈아 가면서 실행시켜 모든 프로세스가 마치 동시에 실행중인것처럼 작동시킨다고 했다.<br><br></p>
<p>무슨 기준으로 어떻게 번갈아갈지를 결정하는 방법이 스케쥴링이고, 기본 토대를 하는 것이 프로세스의 우선순위 이다.<br><br></p>
<p>우선순위를 어떻게 부여할 것인가? 작업중인 프로세스를 끝까지 돌릴것인가 중간에 자원을 뺏을것인가 등 여러 고려법이 있다.<br><br></p>
<p>프로세스를 그냥 크게 나눠보면, CPU작업과, 입출력 작업으로 나눠볼수 있을것이다. CPU작업에는 메모리와 CPU 직접적인 작업이고, 입출력 작업은 키보드, 모니터, 스피커, 하드디스크 등 입출력 장치들의 작업이 완료되기를 기다리는 작업이 많다는것.<br><br></p>
<p>이를 <code>CPU bound process</code> , <code>I/O bound process</code> 로 개념적으로 나눈다. 이렇게 개념적으로 나뉘었을때 우선순위가 높은건 일반적으로 I/O bound process 이다. 
-&gt; 왜? 입출력 바운드면 그만큼 CPU는 좀만 사용하고 바로 대기 상태를 자주 들린다는 소리이다. 이는 곧 우선순위를 높여놔야. 작업효율 증가를 의미한다.<br><br></p>
<p>더 잘게 들어가서 CPU를 사용해야하는 작업은 <code>CPU burst</code> 입출력은 <code>I/O burst</code>라고 용어를 구분한다. <br><br></p>
<h4 id="스케줄링-큐brbr">스케줄링 큐<br><br></h4>
<p>우선순위가 높다고 그저 바로 사용하게 하는 것은 아니다. 근본적으로 스케줄링 큐라는 개념이 존재한다. 우선순위에 의해 스케줄링큐의 순서가 마구 바뀌는 경우도 있고 아닌 경우도 있는데, 일단은 스케줄링 큐에서 줄을 서고, 순서에 맞게 CPU 자원을 사용하는 기회를 받는다고 생각.<br><br></p>
<h4 id="선점형과-비선점형brbr">선점형과 비선점형<br><br></h4>
<p>선점형: preemptive scheduling
사용하고 있는 자원을 강제로 뺏는 방식. 특징. 시스템의 의도는 뺏어서 여러 프로세스들을 적절하게 실행시키기 위함이다. 부작용은 문맥교환이 자주일어남에 따른 오버헤드<br><br></p>
<p>비선점형: non preemptive scheduling
일단 사용하고 있으면 뺏지는 않는 방식. 시스템의 의도는 사용하고 있는 자원에 프로세스가 집중하여 빠르게 끝내고 다른 프로세스가 효율적으로 사용하게 하기 위함. 부작용은 프로세스 기회 불균형<br><br></p>
<h4 id="확인문제brbr-2">확인문제<br><br></h4>
<ol>
<li>4번</li>
<li>준비큐, 대기큐</li>
<li>2번<br><br></li>
</ol>
<h3 id="11-2-cpu-스케줄링-기법brbr">11-2 CPU 스케줄링 기법<br><br></h3>
<h4 id="fcfsbrbr">FCFS<br><br></h4>
<p>First Come First Served : 선입선출과 비슷. 큐에 가장 어울리는 방식.
비선점형. 먼저 온 순서대로 처리됨. <br><br></p>
<p>만약 비효율적인 자원 점유시간으로 프로세스가 들어오게되면, 2클럭이면 끝나는 작업이 늦게 들어왔다고 100클럭을 기다려야 할 수도 있는 상황이 발생함. 이를 호위효과 convoy effect라고 함.<br><br></p>
<h4 id="sjfbrbr">SJF<br><br></h4>
<p>Shortest Job First: 일단 작업이 막 물밀려 오듯 들어올때 가장 작업 속도가 덜 들어가는 작업이 더 높은 우선순위를 받아서 스케쥴링 큐 앞쪽으로 이동되는 기법.<br><br></p>
<p>그렇다고해서 이미 작업중인걸 끊는 개념은 아니다. 즉 비선점형이다.<br><br></p>
<h4 id="rrbrbr">RR<br><br></h4>
<p>Round Robin : FCFS에 타임 슬라이스 개념이 적용됨. 점유가 길어져 타임슬라이스에 걸리게 되면, 해당 프로세스는 남은 작업을 PCB에 저장후 문맥교환이 일어나고 준비큐로 다시 들어가게 됨.<br><br></p>
<p>네트워크 처리에서 많이 보이는 방식이라고 한다<br><br></p>
<h4 id="srtbrbr">SRT<br><br></h4>
<p>Shortest Remaining Time: 최소 잔여 시간 스케줄링. 최소 잔여시간을 가진 프로세스가 항상 우선순위를 높게 가져가는 시스템이다. 선점형 스케쥴링 방식이고, 먼저 들어온게 잔여시간이 길다면, 계속해서 물밀듯이 들어오는 짧은 작업들이 넘쳐난다면 해당 프로세스는 절대 기회를 받지 못한다. 실제 상황이라면 이런 상황이 10초이상 지속되는 상황이 나올정도로 너무나도 컴퓨터가 무리하고 잇다면 10초동안 해당 프로세스는 응답없음으로 작동하게 된다.<br><br></p>
<h4 id="pqbrbr">PQ<br><br></h4>
<p>Priority Queing: 사실 우선순위는 따로 나눌 필요 없는 근본 그자체이다. 그 근본에대한 설명이다. 최소 시간도 아니고, 먼저 들어온것도 아니고, 암튼 운영체제에 의해서 무언가 어떤 요건에 의해 우선순위가 할당되기만 하면 우선순위 스케줄링 방식이다. 진짜 근본이다.<br><br></p>
<p>이런 방식에서 생각해봐야 될 것은 태생이 우선순위 번호가 높아서 후순위이고, 앞서 SRT마냥 최악의 조건이 겹쳐 작은 우선순위의 프로세스들이 물밀듯이 밀려온다면, 해당 프로세스는 멈추게된다. 이를 기아현상 starvation이라고 함. <br><br></p>
<p>이런 스타베이션을 해결하기 위해, Aging 에이징 개념이 추가되어 있다. 에이징이란 마치 나이를 먹듯 일정 시간 이상 큐에 있는 애들은 강제로 우선순위를 낮춰주어 새로 들어오는 애들에게 무한히 밀리는 현상을 방지해준다.<br><br></p>
<h4 id="mlqbrbr">MLQ<br><br></h4>
<p>Multilevel Queue : 다단계 큐 스케줄링. 큐가 하나가 아니라, 우선순위 레벨에 따라 여러 큐를 두고 비슷한 레벨단위끼리 큐를 공유하는 방식이다. <br><br></p>
<p>이는 우선순위가 후순위로 밀리더라도 완전 뒤에 있지않고, 큐자체를 레벨에 따른 횟수 차이는 있겠으나 번갈아가며 실행시켜주기 때문에 후순위 큐도 빠르게 자원을 받을 수 있게 된다.<br><br></p>
<p>이 개념은 어떤 우선순위를 부여할지는 모르겠지만, 일단 우선순위 레벨에 따른 큐가 여러개 존재하는것 그자체로 MLQ 시스템이라 볼 수 있다.<br><br></p>
<h4 id="mfqbrbr">MFQ<br><br></h4>
<p>Multilevel Feedback Queue: MLQ에 피드백이란 개념이 들어간다. 피드백이란 무엇인가? Aging 개념이 추가되어 후순위 레벨에 있는 작업은 더 높은 레벨의 큐로 이동시켜주고, 앞순위 레벨에 있던 작업은 실행되고나서 남은 작업은 레벨을 뒤로 밀어 자원을 덜받게 함으로써 자원을 순환시킨다.<br><br></p>
<p>설계가 가장 복잡해보이고 고려할게 많은데, 요즘 CPU는 이 방식에서 발전된 개념을 사용한다.<br><br></p>
<h4 id="확인문제brbr-3">확인문제<br><br></h4>
<ol>
<li>3번</li>
<li>기아현상, 에이징<br><br></li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[혼공컴운][3주차] CH06~08]]></title>
            <link>https://velog.io/@flower-in-eyes/%ED%98%BC%EA%B3%B5%EC%BB%B4%EC%9A%B43%EC%A3%BC%EC%B0%A8-CH0608</link>
            <guid>https://velog.io/@flower-in-eyes/%ED%98%BC%EA%B3%B5%EC%BB%B4%EC%9A%B43%EC%A3%BC%EC%B0%A8-CH0608</guid>
            <pubDate>Wed, 05 Feb 2025 08:40:24 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>CH06 메모리와 캐시메모리</p>
</blockquote>
<h2 id="06-1-ram의-특징과-종류-brbr">06-1 RAM의 특징과 종류 <br><br></h2>
<h3 id="ram의-특징br">RAM의 특징<br></h3>
<p>휘발성 저장장치: 전류가 차단되면 안에 있는 정보는 전부 사라짐.<br></p>
<h3 id="ram의-용량과-성능-br">RAM의 용량과 성능 <br></h3>
<p>램의 용량이 많을 수록 많은 프로그램을 메모리에 올릴 수 있음. 하지만 필요 이상은 더 이상 성능 향상 기대가 어려움.<br></p>
<h3 id="ram의-종류br">RAM의 종류<br></h3>
<h4 id="drambr">DRAM<br></h4>
<p>Dynamic RAM<br>
동적램인데, 뭐가 동적이냐? -&gt; 주기적으로 내부 축전기의 전류를 흘러주어 충전해야되서 동적램이란다.<br>
-&gt;??? 램자체가 계속해서 전류를 공급해줘야 되는 거 아니야??? <br>
-&gt; 전류 공급은 그냥 기본이고, 축전기 리프레시도 추가로 해줘야 된다는 것.<br>
<br>
이렇게 불편해보여도 단점만 있는게 아니라, 오히려 장점이다.<br>
일단 기본 소비 전류자체가 낮다. 리프레시와 별개로 소비전력자체는 SRAM대비 거의 없는 편<br>
설계 최소 단위가 단순하여 집적도를 높이기 쉽다 == 대용량 늘리기가 용이하다<br>
다만 SRAM 대비 속도는 느리다.<br>
주기억장치로 사용된다<br></p>
<h4 id="srambr">SRAM<br></h4>
<p>Static RAM<br>
전류만 공급하면 동적으로 뭔가 리프레시 같은걸 해줄 필요는 없는 램이라서 정적램이다.<br>
속도는 빠르지만, 복잡성이 커서 집적도를 높이기 어려우니 용량을 늘리기 쉽지 않다.<br>
캐시메모리에 사용된다<br></p>
<h4 id="sdrambr">SDRAM<br></h4>
<p>Synchronous DRAM<br>
DRAM의 일종이다. 그런데 동기화 DRAM이다. 무엇과 동기화 된다는 것인가? CPU 클럭 신호와 동기화 된다는 의미이다. 비로소 현대 CPU와 작업하기 딱인 DRAM이 등장한 것.<br></p>
<h4 id="ddr-sdrambr">DDR SDRAM<br></h4>
<p>Double Data Rate SDRAM<br>
2배 대역폭 SDRAM이다. SDRAM을 다른 말로 DDR SDRAM과 구별하여 Single Data Rate SDRAM 즉 SDR SDRAM 이라고도 한다.<br>
DDR SDRAM&#39;s data rate == 2 * SDR SDRAM&#39;s data rate<br>
DDR2 SDRAM&#39;s data rate == 2 * DDR SDRAM&#39;s data rate == 4 * SDR SDRAM&#39;s data rate<br>
DDR3 SDRAM&#39;s data rate == 2 * DDR2 SDRAM&#39;s data rate == 8 * SDR SDRAM&#39;s data rate<br>
DDR4 SDRAM&#39;s data rate == 2 * DDR3 SDRAM&#39;s data rate == 16 * SDR SDRAM&#39;s data rate<br></p>
<h3 id="확인문제과제br">확인문제(과제)<br></h3>
<pre><code>1. 3번
2. DDR SDRAM, SRAM, DRAM, SDRAM
3. SRAM, DRAM, DRAM, SRAM
4. 2, 2</code></pre><br>

<hr>
<br>

<h2 id="06-2-메모리의-주소-공간-brbr">06-2 메모리의 주소 공간 <br><br></h2>
<h3 id="물리-주소와-논리-주소-br">물리 주소와 논리 주소 <br></h3>
<p>물리주소는 진짜 하드웨어 메모리에 실제로 프로그램이 실려 있는 주소이다. 명령어나 데이터들의 실제 주소이다.<br>
<br>
논리주소는 프로그램과 CPU가 알고 있는 주소이다. 논리적으로 시작주소는 항상 0이고, 0을 기준으로 얼만큼 떨어져 있는지로 프로그램과 CPU는 불러오고 저장하려 한다<br>
<br>
왜냐하면 프로그램 실행할때마다 다를건데 대체 프로그램이 무슨 수로 알고서 자기 자신 주소를 일일히 알고 있어야하는가. 그리고 그렇게 자기 자신의 주소가 굉장히 복잡한 주소라면 그게 가독성이 좋을까?<br>
<br>
이미 앞서 공부했던 것 처럼, <code>베이스 레지스터</code>라는 곳에 해당 프로그램의 물리적인 시작 주소를 저장하고 이걸 <code>Offset</code>으로 사용하며 <code>변위주소지정방식</code> 처럼 offset에 논리 주소를 더해가며 실제 메모리와 CPU는 소통하게 된다.<br>
<br>
이를 담당하는 기관은 MMU(memory management unit)이다. 주소 버스를 반드시 거치게 되어 있는데 메모리에 접근하기 위해 주소버스를 거치기 직전에, 혹은 메모리로 부터 가져올때 주소버스로 부터 온 주소값은 전부 MMU를 통하여 offset이 더해지고 빼진다.<br></p>
<h3 id="메모리-보호-기법-br">메모리 보호 기법 <br></h3>
<p>프로그램에는 일정 길이라는게 있다. 그 정해진 일정길이를 넘어가는 명령어를 한 프로그램에서 작동시키려고 하면, 해당 명령은 일단 인터럽트 트랩에 걸리게 되며, 오차가 있다면 다시 계산하여 정상 작동 시키고, 만약 아니고 치명적이라면, 프로그램은 뻗을것이다.<br>
그 정해진 일정길이값은 <code>한계레지스터</code>에 저장된다.<br></p>
<h3 id="확인-문제br">확인 문제<br></h3>
<pre><code>1. 3번
2. 3번
3. 1번
4. 한계 레지스터, 베이스 레지스터</code></pre><br>

<hr>
<br>

<h2 id="06-3-캐시-메모리-brbr">06-3 캐시 메모리 <br><br></h2>
<h3 id="저장-장치-계층-구조br">저장 장치 계층 구조<br></h3>
<p>CPU에 가까울 수록 빠르고, 비싸고, 용량이 작다.<br>
CPU에 멀 수록 느리고, 싸고, 용량이 크다<br></p>
<h3 id="캐시-메모리-br">캐시 메모리 <br></h3>
<p>레지스터 다음으로 가장 CPU와 가까운 녀석이다. 실제 역할도 메모리 역할을 한다.<br>
CPU는 바로 항상 메모리에 접근하지 않고, 캐시 메모리에 자기가 찾는 데이터가 있는지를 항상 먼저 조회하고 있다면 캐시메모리를 사용한다<br>
<br>
일반적으로 L1, L2, L3 로 구분하며, 해당 녀석들은 빠른 순서이자 CPU에 가까운 순서이다. L1, L2는 코어 내부에 있고, L3는 코어 외부에서 멀티 코어들이 전부 사용가능한 공토 공간으로 사용되는 형태를 일반적으로 취한다.<br></p>
<h3 id="참조-지역성-원리br">참조 지역성 원리<br></h3>
<pre><code>첫째, CPU는 최근에 접근했던 메모리 공간에 다시 접근한다.
둘째, CPU는 접근한 메모리 공간 근처 주소인 이전 혹은 이후 주소에 접근한다.</code></pre><p>위 두가지 원리에 입각하여 캐시 메모리에 올라올 데이터들이 정해진다. 현대 CPU의 캐시 적중률은 85프로 이상이다.<br></p>
<h3 id="확인-문제과제br">확인 문제(과제)<br></h3>
<pre><code>1. 레지스터, 캐시 메모리, 메모리, 보조기억장치
2. 4번</code></pre><hr>
<hr>
<blockquote>
<p>CH07 보조기억장치</p>
</blockquote>
<h2 id="07-1-다양한-보조기억장치brbr">07-1 다양한 보조기억장치<br><br></h2>
<h3 id="하드-디스크-구조br">하드 디스크 구조<br></h3>
<p>HDD: Hard Disk Drive<br>
자기 디스크: magnetic disk <br>
<br>
플래터: platter. 내부의 원판. 양면에 데이터가 기록되고 보통은 플래터가 여러장이 들어있음.<br>
스핀들: spindle. 플래터를 회전시키는 장치<br>
헤드: 플래터 한 면당 하나씩 위치하여 해당 면의 데이터를 기록하고 읽어들일 수 있음<br>
디스크암: 헤드의 깊이를 컨트롤하기 위한 장치<br>
트랙: 센터부터 가장자리까지 일정 두께의 원들이 모여 플래터 원판을 만드는데 이런 원 하나가 트랙<br>
섹터: 최소 데이터 저장 단위 공간. 트랙의 일부분을 담당. 섹터가 여러개가 모여 트랙을 이룸<br>
실린더: 플래터 양면, 그리고 다른 플래터들 전부 같은 xy변위의 트랙들이 존재할것. 그런 트랙들을 묶어서 실린더라고 함. 연속된 데이터를 저장할때는 일단 실린더 단위로 묶여서 연달아 저장됨. 그래야 디스크암의 탐색 운동을 줄일 수 있음.<br>
탐색시간: seek time. 디스크암이 헤더를 움직이는 시간. 찾고자 하는 트랙에 맞게 헤더를 위치시킴 <br>
회전지연: rotational latency. 플래터를 회전시켜 찾고자하는 섹터에 헤더를 위치시키는 시간<br>
전송시간: transfer time. 실제 읽어들여서 cpu까지 도달하는 시간<br>
<br>
다중 헤드 디스크: multiple head disk. 트랙별로 헤드가 위치한다. 예를들어 플래터 하나당 트랙이 3개라면 한 면당 3개. 플래터가 8장이면, 3*8*2 = 48 양면이니까. 이렇게 되면 seek time이 없어지게되고 회전지연만 남게 된다. 고정 헤드 디스크(fixed head disk)라고도 함.<br>
단일 헤드 디스크: single head disk. 디스크암이 움직이며 트랙별로 헤드를 이동시킴. 이동 헤드 디스크라고도함(movable head disk)<br>
<br></p>
<h3 id="플래시-메모리br">플래시 메모리<br></h3>
<p>usb, sd카드, ssd, rom 등 다양한 구간에서 사용 중<br>
셀: cell. 플래시 메모리에서 데이터를 저장하는 가장 작은 단위. SLC(single level cell) MLC(multiple level cell) TLC(triple level cell) 등을 나눌때 cell을 어떻게 설계하냐에 따라서 설계가 달라진다<br>
SLC는 한 cell이 1bit를 표현, 0과 1 총 2가지 $2^1$ MLC는 2bit. TLC는 3bit이다. SLC가 가장 용량을 늘리기 어렵고, TLC가 용량을 늘리기 쉽다.<br>
<br>
셀<code>cell</code>들이 모여 페이지<code>page</code>를 이루고, 페이지가 모여 블록<code>block</code>을 이루고, 블록이 모여 플레인<code>plane</code>을 이루고, 플레인이 모여 다이<code>die</code>를 이룬다.<br>
읽기 쓰기의 최소 단위가 페이지이다.<br>
삭제의 최소 단위는 블록이다.<br>
페이지는 총 3가지 상태를 가진다. free, valid, invalid<br>
free: 자유롭게 읽고 쓰고 할 수 있는 상태이다. 비점유 상태.<br>
valid: 유효한 데이터가 페이지를 차지하고 있는 상태.<br>
invalid: 데이터가 있긴한데, 쓰레기 데이터가 차지하고 있는 상태.<br>
<br></p>
<h4 id="데이터-교체-방법br">데이터 교체 방법<br></h4>
<p>총 4개의 페이지를 담을 수 있는 블록이 있다고 했을때 A B C 가 순서대로 들어가 있는 상황. 이때 A를 변경하여 A&#39;로 만드는 방법은 A를 invalid 상태로 만들어 버리고 남은 페이지에 A&#39;를 추가하여 A&#39; B C를 저장하는 블록으로 만드는 방법을 취한다.<br>
A페이지를 직접 지울 수 없다. 왜냐하면 삭제의 단위는 블록이기 때문<br>
하지만 이렇게 되면 용량을 실제 사용도 안하는 데이터들이 너무 많이 차지하게 됨.<br>
그래서 가비지 컬렉터라는 기능을 이용하여. 블록을 검사하여 Valid 페이지만 살려서 따로 복사한뒤에 이전 블록을 비로소 삭제해버리는 기능을 자동으로 제공하도록 발전됨.<br>
<br></p>
<h3 id="확인-문제br-1">확인 문제<br></h3>
<pre><code>1. 플래터,스핀들,헤드
2. 2번</code></pre><br>

<hr>
<br>

<h2 id="07-2-raidbrbr">07-2 RAID<br><br></h2>
<h3 id="raid의-정의br">RAID의 정의<br></h3>
<p>Rebundent Array of Independent Disks: 복수 배열 독립 디스크<br>
여러개의 디스크로 커다란 하나의 디스크를 구성하는 방법<br>
가격이 저렴할 뿐만 아니라, 읽고 쓰기 행위 자체를 여러개가 분산해서 담당하게 되기때문에 성능향상 효과도 있음<br><br></p>
<h3 id="raid의-종류br">RAID의 종류<br></h3>
<h4 id="raid0br">RAID0<br></h4>
<p>진짜 연속된 데이터가 있으면 분산된 만큼 하나씩 분산해서 쓰고 읽는 방법. 가장 단순하고, 가장 군더더기 없이 읽고 씀. 하지만 디스크 하나라도 고장나면 데이터가 손실되게됨.<br></p>
<h4 id="raid1br">RAID1<br></h4>
<p>RAID0를 2개로 복제하여 복사본을 항상 쓰는 방법. 디스크 중 하나가 고장 나도 복제본 디스크가 있기 때문에 안정성 확보. 그런데 그만큼 용량은 비효율적.<br></p>
<h4 id="raid4br">RAID4<br></h4>
<p>연속된 데이터들을  RAID0처럼 분산 저장하는건 맞는데 이때 패리티 정보를 담는 전용 디스크를 두는 방법. 이 패리티 데이터로 인해 다른 디스크에 저장된 데이터에 오류는 없는지 체크가능하고, 복구도 가능함.<br>
하지만, 패리티 정보를 누적하여 만들기 위해서 다른 디스크에 데이터 쓰기가 이뤄질때 마다 한번씩 페리티 정보도 써야하기 때문에 패리티 디스크에 과부하가 걸리는 구조.<br></p>
<h4 id="raid5br">RAID5<br></h4>
<p>패리티 디스크에 과부하가 걸리는 구조를 깨기 위해. 모든 디스크가 데이터를 저장하는 역할 뿐만아니라 분산해서 패리티 정보를 저장하는 방식. <br></p>
<h4 id="raid6br">RAID6<br></h4>
<p>패리티 데이터 자체에대한 복구까지 고려된 방식. 각기 다른 디스크에 같은 패리티 데이터를 복제하여 저장하도록 담당시킨다. 당연히 쓰기에 더 많은 자원이 든다.<br><br></p>
<h3 id="확인-문제br-2">확인 문제<br></h3>
<pre><code>1. 2번
2. 3번
3. RAID6</code></pre><br>

<hr>
<hr>
<blockquote>
<p>CH08 입출력장치</p>
</blockquote>
<h2 id="08-1-장치-컨트롤러와-장치-드라이버brbr">08-1 장치 컨트롤러와 장치 드라이버<br><br></h2>
<h3 id="장치-컨트롤러br">장치 컨트롤러<br></h3>
<p>다양한 여러 장치들은 각자의 속도, 처리량, 요구 데이터 등이 전부 다르기 때문에 이걸 CPU가 각 장치마다 맞춤형으로 맞춰 줄 수가 없다. 그래서 중간 다리 역할을 하는 녀석이 장치 컨트롤러이다.<br>
장치 컨트롤러를 그러기 위해 기본적으로 저장 장치가 필요하다. CPU에 보낼 데이터, 지금 장치의 상태 등을 저장해야 되기 때문임. 장치 컨트롤러 내부에는 데이터 레지스터, 상태 레지스터, 제어 레지스터가 있음<br>
데이터 레지스터: 입출력 장치가 CPU에 보내고 싶은 데이터를 모아 놓는 공간. 출력의 경우에는 그 반대<br>
상태 레지스터: 입출력 장치가 대기 상태인지, 아직 막 작업 중인 상태인지 등을 저장<br>
제어 레지스터: CPU가 입출력 장치에 보낸 명령을 저장하는 공간<br></p>
<h3 id="장치-드라이버br">장치 드라이버<br></h3>
<p>장치 컨트롤러가 CPU와 다양한 입출력 장치들이 서로 소통하기 위한 하드웨어적 장치였다면, 장치 드라이버는 중개 소프트웨어이다.<br>
OS가 기본적으로 장치 드라이버를 인식하여 설치해야하며, 설치가 안되었다면, 그 어떤 입출력 장치도 소통할 수 없다.<br></p>
<h3 id="확인-문제br-3">확인 문제<br></h3>
<pre><code>1. 1번, 3번
2. 2번
3. 장치 컨트롤러, 프로그램
4. 2번</code></pre><br>

<hr>
<br>

<h2 id="08-2-다양한-입출력-방법brbr">08-2 다양한 입출력 방법<br><br></h2>
<h3 id="프로그램-입출력br">프로그램 입출력<br></h3>
<p>프로그램이 입출력 장치를 컨트롤 하는 경우에 프로그램 입출력 방식이라고 함.<br>
장치 컨트롤러 내부에는 CPU와 소통하기 위한 레지스터들이 있는데, 제어 레지스터에 명령어를 쓰고, 그 명령어로 입출력 장치가 인식하여 상태 레지스터가 바뀌고, 상태 레지스터가 바뀌면 CPU가 입출력 장치에 보내고 싶은 데이터가 써지거나 혹은 데이터 레지스터에 있는 데이터를 CPU가 읽는 방식으로 동작하게됨.<br>
그런데 여기서 결국 CPU는 메인보드에 부착된 어떤 입출력 장치의 장치 컨트롤러의 레지스터에 접근하고자 할때는 고유한 주소값으로 접근해야 될텐데. 그 방법이 두 가지가 있음. <br>
첫째, CPU는 메모리와 소통한다. 이런 메모리와 소통하는 기존 방식과 다르지 않은 명령어와 주소로 입출력 장치와 소통하는 memory mapped I/O 방식이다. 메모리 일부 공간에 입출력 장치 레지스터의 주소랑 메핑된 공간을 할당하여, 마치 그 공간이 장치 컨트롤러의 공간인냥 사용하는 방법<br>
둘째, 메모리에 접근하는 방법은 시스템 버스의 데이터 버스, 제어버스, 주소버스 를 이용하여 필요할때 메모리에 접근하는 방식이다. 이것처럼 입출력 장치들을 묶어서 소통할 수 있는 버스를 입출력장치 버스를 둠으로 써 모든 입출력 장치에 접근하는 방법을 뚫는 방법. 이는 메모리와 소통할때 쓰이는 일반적인 명령어 집합이 아닌 다른 명령어 특히 다른 오퍼랜드를 사용 할 수 밖에 없는 방식이다. 이를 isolated I/O 고립형 입출력 방식이라고 한다.<br></p>
<h3 id="인터럽트-기반-입출력br">인터럽트 기반 입출력<br></h3>
<p>프로그램이 인터럽트를 발생시킬 수도 있고, 하드웨어가 인터럽트를 발생시킬 수도 있다. 하여간 인터럽트를 통해 CPU가 클럭 신호마다 체크하여 입출력 장치와 적절한 소통을 하는 방식이다.<br>
그런데 입출력 장치가 한두개도 아니고, 동시 다발적으로 특히 같은 타이밍에 CPU에 마구 인터럽트를 던져 놓는 상황은 충분히 발생한다. 이를 컨트롤하기 위해 PIC Programmable Interrupt Controller 라는 하드웨어가 메인보드에 있어서 CPU에게 전달될 인터럽트들을 제어하는 중개 역할을 한다.<br>
항상 과장되게 극단적으로 생각해야한다. 입출력장치 하드웨어는 수백개가 존재할 수 있다. 이를 PIC하나가 감당하게 하는 설계를 하지 않는다. PIC는 상위 PIC와 연결되어 어떤 하위 입출력 장치 그룹들의 인터럽트들을 우선 처리할지 등을 또 컨트롤하는 구조를 취한다.<br></p>
<h3 id="dma-입출력br">DMA 입출력<br></h3>
<p>Direct Memory Access Controller라는  하드웨어를 통하여 입출력장치가 메모리에 접근해야할때 CPU가 두번 세번 일하는걸 방지한다.<br>
CPU의 부담을 덜어서 간단한 단순 동작을 대신 처리하게 하는 장치이다.<br>
CPU는 DMA 컨트롤러에 처리해야할 명령들을 전달하고, 해당 명령을 이용하여 입출력장치와 소통, 제어 레지스터, 상태 레지스터, 데이터 레지스터를 모두 사용한 결과가 완료되면, 그제서야 CPU에 일처리 다했어요 인터럽트만을 CPU에게 쏜다. CPU는 다른 복잡한 작업을 하는 동안 입출력 장치 동작 정도는 DMA 컨트롤러가 대신해주는 것<br></p>
<h3 id="입출력-버스">입출력 버스</h3>
<p>DMA 뿐만 아니라, 입출력 장치가 무언가를 하여 transfer 즉 통신을 할때는 반드시 메인보드의 버스를 이용해야 한다. 그런데 버스는 고속도로가 아닌 기차 선로여서 한번에 한 장치만 점유할 수 있는 구조이다.<br>
만약 입출력 버스라는게 없다면, 시스템 버스를 사용해야되어 CPU가 제대로 일을 할 수가 없게 된다.<br>
그래서 등장한게 입출력버스이고, 대표적인건 PCI 버스가 있다. Peripheral Component Interconnect 그 발전형인 PCI Express PCIe 버스가 현재 주류이다.<br></p>
<h3 id="확인-문제br-4">확인 문제<br></h3>
<pre><code>1. 2번
2. A 다음 B
3. 3번
4. 메모리 맵 입출력 방식
5. 고립형 입출력 방식</code></pre><br>

<hr>
<br>


]]></description>
        </item>
    </channel>
</rss>