<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>FlyingCStudent.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Mon, 23 Mar 2026 03:49:03 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <copyright>Copyright (C) 2019. FlyingCStudent.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/na_itsso" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[현대오토에버]]></title>
            <link>https://velog.io/@na_itsso/%ED%98%84%EB%8C%80%EC%98%A4%ED%86%A0%EC%97%90%EB%B2%84</link>
            <guid>https://velog.io/@na_itsso/%ED%98%84%EB%8C%80%EC%98%A4%ED%86%A0%EC%97%90%EB%B2%84</guid>
            <pubDate>Mon, 23 Mar 2026 03:49:03 GMT</pubDate>
            <description><![CDATA[<p>현대오토에버 모빌리티 스쿨 정리</p>
<p><a href="https://curly-pufferfish-7ca.notion.site/SW-2cd6b65d5a698020a20af935434cbaec">https://curly-pufferfish-7ca.notion.site/SW-2cd6b65d5a698020a20af935434cbaec</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[ Hybrid RAG]]></title>
            <link>https://velog.io/@na_itsso/Hybrid-RAG</link>
            <guid>https://velog.io/@na_itsso/Hybrid-RAG</guid>
            <pubDate>Tue, 10 Mar 2026 14:25:31 GMT</pubDate>
            <description><![CDATA[<p>기타 - Hybrid RAG </p>
<h1 id="hybrid-rag-도입-전후-비교">Hybrid RAG 도입 전/후 비교</h1>
<hr>
<h2 id="1-개념적-비교">1. 개념적 비교</h2>
<h3 id="before-pure-vector-rag">Before: Pure Vector RAG</h3>
<ul>
<li><strong>검색 방식</strong><ul>
<li>Gemini <code>text-embedding-004</code>로 쿼리 임베딩 생성</li>
<li>ChromaDB <code>market_prices</code> 컬렉션에 대해 <strong>vector similarity 검색만 수행</strong></li>
<li><code>distance</code>(코사인 거리)에 따라 상위 <code>top_k</code> 결과를 그대로 사용</li>
</ul>
</li>
<li><strong>장점</strong><ul>
<li>의미 기반 유사도 검색에 강함</li>
<li>임베딩 모델만 잘 학습되어 있으면 자연어 쿼리에 유연하게 대응</li>
</ul>
</li>
<li><strong>단점</strong><ul>
<li>숫자, 브랜드명, 기능명 같은 <strong>정확 키워드 매칭</strong>에 약함</li>
<li>짧은 텍스트/희소 데이터에서 <strong>리콜이 떨어질 수 있음</strong></li>
<li>쿼리와 같은 단어를 포함하지 않아도 임베딩이 비슷하면 상위에 오를 수 있음</li>
</ul>
</li>
</ul>
<hr>
<h3 id="after-hybrid-rag-vector--lexical-re-ranking">After: Hybrid RAG (Vector + Lexical Re-ranking)</h3>
<ul>
<li><strong>검색 방식</strong><ol>
<li>기존처럼 <strong>벡터 검색</strong>으로 <code>top_k * 3</code> 개의 후보 문서 가져오기</li>
<li>각 후보에 대해:<ul>
<li><code>vector_score = 1 - distance</code></li>
<li><code>lexical_score</code> = 쿼리 토큰과 문서/메타데이터 토큰의 겹침 비율</li>
<li><code>hybrid_score = 0.6 * vector_score + 0.4 * lexical_score</code></li>
</ul>
</li>
<li><code>hybrid_score</code> 기준으로 정렬 후 상위 <code>top_k</code>만 최종 결과로 사용</li>
</ol>
</li>
<li><strong>장점</strong><ul>
<li>의미 기반 검색(벡터) + <strong>정확 키워드 매칭(lexical)</strong>을 동시에 활용</li>
<li>가격/페이지 수/브랜드명/기능명 등이 쿼리에 포함될 때 <strong>정확하게 매칭되는 문서에 가중치 부여</strong></li>
<li>짧은 설명이나 희소 데이터에서도 키워드 매칭으로 리콜 보강</li>
</ul>
</li>
<li><strong>단점/Trade-off</strong><ul>
<li>후보 수(<code>top_k * 3</code>)를 늘려서 한 번 더 파이썬 레벨에서 재랭킹하므로 약간의 CPU 비용 증가</li>
<li>아주 큰 컬렉션에서 <code>candidate_k</code>를 너무 키우면 속도에 영향이 있을 수 있음 (현재는 3배 수준으로 안전한 범위)</li>
</ul>
</li>
</ul>
<hr>
<h2 id="2-코드-레벨-비교">2. 코드 레벨 비교</h2>
<h3 id="before-search_similar_deals-순수-벡터">Before: <code>search_similar_deals</code> (순수 벡터)</h3>
<pre><code class="language-python">def search_similar_deals(self, query: str, category: Optional[str] = None, top_k: int = 5):
    # 1. 쿼리 임베딩 생성
    query_embedding = self.create_embedding(query)

    # 2. ChromaDB 검색 (카테고리 필터 적용)
    where_filter = {&quot;category&quot;: category} if category else None

    results = self.collection.query(
        query_embeddings=[query_embedding],
        n_results=top_k,
        where=where_filter
    )

    # 3. 결과 포맷팅
    similar_deals = []
    if results[&#39;ids&#39;] and len(results[&#39;ids&#39;][0]) &gt; 0:
        for i in range(len(results[&#39;ids&#39;][0])):
            deal = {
                &quot;id&quot;: results[&#39;ids&#39;][0][i],
                &quot;metadata&quot;: results[&#39;metadatas&#39;][0][i],
                &quot;distance&quot;: results[&#39;distances&#39;][0][i],
                &quot;document&quot;: results[&#39;documents&#39;][0][i]
            }
            similar_deals.append(deal)

    return similar_deals</code></pre>
<hr>
<h3 id="after-search_similar_deals-hybrid-vector--lexical">After: <code>search_similar_deals</code> (Hybrid: Vector + Lexical)</h3>
<p>핵심 변화 포인트만 요약:</p>
<pre><code class="language-python">def search_similar_deals(self, query: str, category: Optional[str] = None, top_k: int = 5):
    # 1. 쿼리 임베딩 생성
    query_embedding = self.create_embedding(query)

    # 2. 1차 벡터 검색 (후속 재랭킹을 위해 top_k 보다 넉넉하게 가져옴)
    where_filter = {&quot;category&quot;: category} if category else None
    candidate_k = max(top_k * 3, top_k)

    results = self.collection.query(
        query_embeddings=[query_embedding],
        n_results=candidate_k,
        where=where_filter
    )
    # 3. 질의/문서 토큰화 + lexical score 계산
    def normalize_text(text: str) -&gt; List[str]:
        text = text.lower()
        text = re.sub(r&quot;[^a-z0-9가-힣\s]&quot;, &quot; &quot;, text)
        tokens = [t for t in text.split() if len(t) &gt; 1]
        return tokens
    query_tokens = set(normalize_text(query))
    def lexical_score(doc_text: str) -&gt; float:
        if not query_tokens:
            return 0.0
        doc_tokens = set(normalize_text(doc_text))
        if not doc_tokens:
            return 0.0
        overlap = query_tokens &amp; doc_tokens
        return len(overlap) / len(query_tokens)
    # 4. 벡터 스코어 + lexical 스코어 결합
    hybrid_candidates = []
    for i in range(len(ids)):
        ...
        vector_score = 1.0 - float(distance)
        combined_text = f\&quot;{title} {category_text} {document[:1000]}\&quot;
        lex_score = lexical_score(combined_text)
        hybrid_score = 0.6 * vector_score + 0.4 * lex_score
        hybrid_candidates.append({...})
    # 5. hybrid_score 기준 상위 top_k 선택
    hybrid_candidates.sort(key=lambda x: x[\&quot;hybrid_score\&quot;], reverse=True)
    top_candidates = hybrid_candidates[:top_k]
    ...
    return similar_deals</code></pre>
<hr>
<h2 id="3-기대-효과-ppt용-bullet-point">3. 기대 효과 (PPT용 Bullet Point)</h2>
<p><strong>Before (Pure Vector)</strong>  </p>
<ul>
<li>의미 기반 유사도에는 강하지만,  </li>
<li>가격/페이지 수/기능명/브랜드명 같은 <strong>정확 키워드</strong>가 반영되지 않을 수 있음  </li>
<li>짧은 텍스트나 희소한 데이터에서 <strong>리콜 부족</strong> 문제 발생 가능  </li>
<li>RAG 실패 시, 오케스트레이션 에이전트가 아무리 잘 짜여 있어도 후보군 자체가 부족해짐</li>
<li><em>After (Hybrid Vector + Lexical)*</em>  </li>
<li><strong>벡터 스코어 + 키워드 스코어</strong>를 결합해 더 안정적인 검색 결과 제공  </li>
<li>쿼리 내부의 핵심 단어(예: &quot;WordPress&quot;, &quot;3 hours&quot;, &quot;logo&quot;, &quot;landing page&quot;)가 실제 문서/타이틀에 포함된 경우 우선순위 상승  </li>
<li>짧은 설명/희소 데이터에서도 키워드 겹침으로 리콜 보강  </li>
<li>오케스트레이션 에이전트가 선택할 수 있는 <strong>후보군 품질과 다양성</strong>이 상승 → 전체 체인 안정성 증가</li>
</ul>
<hr>
<h2 id="4-측정비교-아이디어-보고서용">4. 측정/비교 아이디어 (보고서용)</h2>
<ol>
<li><strong>Top-k Precision</strong>  <ul>
<li>특정 쿼리 셋(예: “워드프레스 수정 3시간”, “로고 디자인 패키지”, “당근마켓 아이폰 13 프로”)에 대해  </li>
<li>사람이 라벨링한 <strong>정답 거래들</strong>이 top-5 안에 포함되는 비율 비교</li>
</ul>
</li>
<li><strong>클릭/선택 로그 기반</strong> (실제 사용자 데이터 생긴 후)<ul>
<li>제안된 협상안들 중 실제로 선택된 옵션이  </li>
<li>Hybrid RAG가 추천한 상위 후보에서 얼마나 자주 나오는지 측정</li>
</ul>
</li>
<li><strong>실패 케이스 분석</strong><ul>
<li>“관련 거래 없음”으로 떨어졌던 케이스를 다시 돌려보고  </li>
<li>Hybrid 적용 후 <strong>유사 사례가 새로 잡히는 비율</strong> 확인</li>
</ul>
</li>
</ol>
<hr>
<h2 id="5-정리-문구-한-줄-요약">5. 정리 문구 (한 줄 요약)</h2>
<ul>
<li><strong>Before</strong>: “의미 기반(Vector-only) RAG → 자연어는 잘 잡지만, 키워드/숫자/짧은 텍스트에 약함”  </li>
<li><strong>After</strong>: “Hybrid RAG (Vector + Lexical Re-ranking) → 의미 + 키워드 둘 다 반영해, 오케스트레이션 에이전트가 믿고 쓸 수 있는 후보군 제공”</li>
</ul>
<h1 id="hybrid-rag-도입-전후-비교-정리">Hybrid RAG 도입 전/후 비교 정리</h1>
<h2 id="보고서ppt에-바로-쓸-수-있도록-rag-구조의-before--after를-정리한-문서입니다">보고서/PPT에 바로 쓸 수 있도록, RAG 구조의 <strong>Before / After</strong>를 정리한 문서입니다.</h2>
<h2 id="1-개념적-비교-1">1. 개념적 비교</h2>
<h3 id="before-pure-vector-rag-1">Before: Pure Vector RAG</h3>
<ul>
<li><strong>검색 방식</strong><ul>
<li>Gemini <code>text-embedding-004</code>로 쿼리 임베딩 생성</li>
<li>ChromaDB <code>market_prices</code> 컬렉션에 대해 <strong>vector similarity 검색만 수행</strong></li>
<li><code>distance</code>(코사인 거리)에 따라 상위 <code>top_k</code> 결과를 그대로 사용</li>
</ul>
</li>
<li><strong>장점</strong><ul>
<li>의미 기반 유사도 검색에 강함</li>
<li>임베딩 모델만 잘 학습되어 있으면 자연어 쿼리에 유연하게 대응</li>
</ul>
</li>
<li><strong>단점</strong><ul>
<li>숫자, 브랜드명, 기능명 같은 <strong>정확 키워드 매칭</strong>에 약함</li>
<li>짧은 텍스트/희소 데이터에서 <strong>리콜이 떨어질 수 있음</strong></li>
<li>쿼리와 같은 단어를 포함하지 않아도 임베딩이 비슷하면 상위에 오를 수 있음</li>
</ul>
</li>
</ul>
<hr>
<h3 id="after-hybrid-rag-vector--lexical-re-ranking-1">After: Hybrid RAG (Vector + Lexical Re-ranking)</h3>
<ul>
<li><strong>검색 방식</strong><ol>
<li>기존처럼 <strong>벡터 검색</strong>으로 <code>top_k * 3</code> 개의 후보 문서 가져오기</li>
<li>각 후보에 대해:<ul>
<li><code>vector_score = 1 - distance</code></li>
<li><code>lexical_score</code> = 쿼리 토큰과 문서/메타데이터 토큰의 겹침 비율</li>
<li><code>hybrid_score = 0.6 * vector_score + 0.4 * lexical_score</code></li>
</ul>
</li>
<li><code>hybrid_score</code> 기준으로 정렬 후 상위 <code>top_k</code>만 최종 결과로 사용</li>
</ol>
</li>
<li><strong>장점</strong><ul>
<li>의미 기반 검색(벡터) + <strong>정확 키워드 매칭(lexical)</strong>을 동시에 활용</li>
<li>가격/페이지 수/브랜드명/기능명 등이 쿼리에 포함될 때 <strong>정확하게 매칭되는 문서에 가중치 부여</strong></li>
<li>짧은 설명이나 희소 데이터에서도 키워드 매칭으로 리콜 보강</li>
</ul>
</li>
<li><strong>단점/Trade-off</strong><ul>
<li>후보 수(<code>top_k * 3</code>)를 늘려서 한 번 더 파이썬 레벨에서 재랭킹하므로 약간의 CPU 비용 증가</li>
<li>아주 큰 컬렉션에서 <code>candidate_k</code>를 너무 키우면 속도에 영향이 있을 수 있음 (현재는 3배 수준으로 안전한 범위)</li>
</ul>
</li>
</ul>
<hr>
<h2 id="2-코드-레벨-비교-1">2. 코드 레벨 비교</h2>
<h3 id="before-search_similar_deals-순수-벡터-1">Before: <code>search_similar_deals</code> (순수 벡터)</h3>
<pre><code class="language-python">def search_similar_deals(self, query: str, category: Optional[str] = None, top_k: int = 5):
    # 1. 쿼리 임베딩 생성
    query_embedding = self.create_embedding(query)

    # 2. ChromaDB 검색 (카테고리 필터 적용)
    where_filter = {&quot;category&quot;: category} if category else None

    results = self.collection.query(
        query_embeddings=[query_embedding],
        n_results=top_k,
        where=where_filter
    )

    # 3. 결과 포맷팅
    similar_deals = []
    if results[&#39;ids&#39;] and len(results[&#39;ids&#39;][0]) &gt; 0:
        for i in range(len(results[&#39;ids&#39;][0])):
            deal = {
                &quot;id&quot;: results[&#39;ids&#39;][0][i],
                &quot;metadata&quot;: results[&#39;metadatas&#39;][0][i],
                &quot;distance&quot;: results[&#39;distances&#39;][0][i],
                &quot;document&quot;: results[&#39;documents&#39;][0][i]
            }
            similar_deals.append(deal)

    return similar_deals</code></pre>
<hr>
<h3 id="after-search_similar_deals-hybrid-vector--lexical-1">After: <code>search_similar_deals</code> (Hybrid: Vector + Lexical)</h3>
<p>핵심 변화 포인트만 요약:</p>
<pre><code class="language-python">def search_similar_deals(self, query: str, category: Optional[str] = None, top_k: int = 5):
    # 1. 쿼리 임베딩 생성
    query_embedding = self.create_embedding(query)

    # 2. 1차 벡터 검색 (후속 재랭킹을 위해 top_k 보다 넉넉하게 가져옴)
    where_filter = {&quot;category&quot;: category} if category else None
    candidate_k = max(top_k * 3, top_k)

    results = self.collection.query(
        query_embeddings=[query_embedding],
        n_results=candidate_k,
        where=where_filter
    )
    # 3. 질의/문서 토큰화 + lexical score 계산
    def normalize_text(text: str) -&gt; List[str]:
        text = text.lower()
        text = re.sub(r&quot;[^a-z0-9가-힣\s]&quot;, &quot; &quot;, text)
        tokens = [t for t in text.split() if len(t) &gt; 1]
        return tokens
    query_tokens = set(normalize_text(query))
    def lexical_score(doc_text: str) -&gt; float:
        if not query_tokens:
            return 0.0
        doc_tokens = set(normalize_text(doc_text))
        if not doc_tokens:
            return 0.0
        overlap = query_tokens &amp; doc_tokens
        return len(overlap) / len(query_tokens)
    # 4. 벡터 스코어 + lexical 스코어 결합
    hybrid_candidates = []
    for i in range(len(ids)):
        ...
        vector_score = 1.0 - float(distance)
        combined_text = f\&quot;{title} {category_text} {document[:1000]}\&quot;
        lex_score = lexical_score(combined_text)
        hybrid_score = 0.6 * vector_score + 0.4 * lex_score
        hybrid_candidates.append({...})
    # 5. hybrid_score 기준 상위 top_k 선택
    hybrid_candidates.sort(key=lambda x: x[\&quot;hybrid_score\&quot;], reverse=True)
    top_candidates = hybrid_candidates[:top_k]
    ...
    return similar_deals</code></pre>
<hr>
<h2 id="3-기대-효과-ppt용-bullet-point-1">3. 기대 효과 (PPT용 Bullet Point)</h2>
<p><strong>Before (Pure Vector)</strong>  </p>
<ul>
<li>의미 기반 유사도에는 강하지만,  </li>
<li>가격/페이지 수/기능명/브랜드명 같은 <strong>정확 키워드</strong>가 반영되지 않을 수 있음  </li>
<li>짧은 텍스트나 희소한 데이터에서 <strong>리콜 부족</strong> 문제 발생 가능  </li>
<li>RAG 실패 시, 오케스트레이션 에이전트가 아무리 잘 짜여 있어도 후보군 자체가 부족해짐</li>
<li><em>After (Hybrid Vector + Lexical)*</em>  </li>
<li><strong>벡터 스코어 + 키워드 스코어</strong>를 결합해 더 안정적인 검색 결과 제공  </li>
<li>쿼리 내부의 핵심 단어(예: &quot;WordPress&quot;, &quot;3 hours&quot;, &quot;logo&quot;, &quot;landing page&quot;)가 실제 문서/타이틀에 포함된 경우 우선순위 상승  </li>
<li>짧은 설명/희소 데이터에서도 키워드 겹침으로 리콜 보강  </li>
<li>오케스트레이션 에이전트가 선택할 수 있는 <strong>후보군 품질과 다양성</strong>이 상승 → 전체 체인 안정성 증가</li>
</ul>
<hr>
<h2 id="4-측정비교-아이디어-보고서용-1">4. 측정/비교 아이디어 (보고서용)</h2>
<ol>
<li><strong>Top-k Precision</strong>  <ul>
<li>특정 쿼리 셋(예: “워드프레스 수정 3시간”, “로고 디자인 패키지”, “당근마켓 아이폰 13 프로”)에 대해  </li>
<li>사람이 라벨링한 <strong>정답 거래들</strong>이 top-5 안에 포함되는 비율 비교</li>
</ul>
</li>
<li><strong>클릭/선택 로그 기반</strong> (실제 사용자 데이터 생긴 후)<ul>
<li>제안된 협상안들 중 실제로 선택된 옵션이  </li>
<li>Hybrid RAG가 추천한 상위 후보에서 얼마나 자주 나오는지 측정</li>
</ul>
</li>
<li><strong>실패 케이스 분석</strong><ul>
<li>“관련 거래 없음”으로 떨어졌던 케이스를 다시 돌려보고  </li>
<li>Hybrid 적용 후 <strong>유사 사례가 새로 잡히는 비율</strong> 확인</li>
</ul>
</li>
</ol>
<hr>
<h2 id="5-정리-문구-한-줄-요약-1">5. 정리 문구 (한 줄 요약)</h2>
<ul>
<li><strong>Before</strong>: “의미 기반(Vector-only) RAG → 자연어는 잘 잡지만, 키워드/숫자/짧은 텍스트에 약함”  </li>
<li><strong>After</strong>: “Hybrid RAG (Vector + Lexical Re-ranking) → 의미 + 키워드 둘 다 반영해, 오케스트레이션 에이전트가 믿고 쓸 수 있는 후보군 제공”</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[SWEA] 1247. 최적경로]]></title>
            <link>https://velog.io/@na_itsso/SWEA-1247.-%EC%B5%9C%EC%A0%81%EA%B2%BD%EB%A1%9C</link>
            <guid>https://velog.io/@na_itsso/SWEA-1247.-%EC%B5%9C%EC%A0%81%EA%B2%BD%EB%A1%9C</guid>
            <pubDate>Thu, 20 Mar 2025 23:27:06 GMT</pubDate>
            <description><![CDATA[<p>최적 경로: 모든 노드를 지났을떄 최단 경로
최단 경로: 모든 노드가 아님</p>
<p>표준 TSP: 다 돌고,다시 돌아오는 거</p>
<p>거리 계산: 매번 재귀에서 하는 것 보단 배열에 저장하고, 참조하는게 더 나음.
(두 점 조합- for문으로 계산)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[day12] Segment Tree & Fenwick Tree]]></title>
            <link>https://velog.io/@na_itsso/day12-Segment-Tree-Fenwick-Tree</link>
            <guid>https://velog.io/@na_itsso/day12-Segment-Tree-Fenwick-Tree</guid>
            <pubDate>Wed, 19 Mar 2025 11:49:40 GMT</pubDate>
            <description><![CDATA[<h2 id="segment-tree">Segment Tree</h2>
<ul>
<li>크기 주로 4를 곱해서 사용</li>
<li>tree[N] ~ tree[2*N -1] : leaf node</li>
<li>tree[1] ~ tree[N-1] : 중간 노드</li>
<li>리프 노드가 N부터 시작하므로, 트리의 구조는 여전히 1-based 인덱스처럼 동작.</li>
<li>N이 홀수든 짝수든, 부모 인덱스 k에 대해 2<em>k(짝수), 2</em>k+1(홀수) 규칙은 변하지 않음.</li>
<li>1-based 트리에서 자식 쌍은 항상 2<em>k와 2</em>k+1.</li>
<li>pos / 2로 부모를 찾고, pos ^ 1은 반대 자식을 정확히 가리킴.<h3 id="방법1-tree_size--n으로-두기">방법1: tree_size = N으로 두기</h3>
<pre><code class="language-cpp">#include &lt;stdio.h&gt;
#include &lt;string.h&gt; //memset용
#define NMAX 1000
</code></pre>
</li>
</ul>
<p>int tsize = NMAX;
int segTree[2 * NMAX];
int src[NMAX]; 
int N;</p>
<p>void update(int pos, int val) {
    pos += tsize; // 0번 -&gt; tsize로 변환
    segTree[pos] = val;
    while (pos &gt; 1) {
        int par = pos / 2;
        int sibling = pos ^ 1;
        segTree[par] = segTree[sibling] + segTree[pos];
        pos = par;
    }
}
//l번 index부터 r번 index까지의 구간합
int query(int l, int r) {
    int res = 0;
    l += tsize; r += tsize;
    while (l &lt;= r) {
        //left가 홀수면? 오른쪽 자식
        if (l % 2 == 1) {
            res += segTree[l];
            l += 1;
        }
        //right가 짝수면? 왼쪽 자식
        if (r % 2 == 0) {
            res += segTree[r];
            r -= 1;
        }
        l /= 2; r /= 2;
    }
    return res;
}</p>
<p>int main() {
    N = 10;
    tsize = N;
    for (int i = 0; i &lt; N; ++i) src[i] = i;
    memset(segTree, 0, sizeof(segTree)); 
    // N ~ 부터는 단말노드
    for (int i = 0; i &lt; N; ++i) {
        segTree[tsize + i] = src[i];
    }
    //1 ~ N-1 까지는 구간합 노드들
    for (int i = N - 1; i &gt; 0; --i) {
        segTree[i] = segTree[i * 2] + segTree[i * 2 + 1];
    }</p>
<pre><code>int left = 3;
int right = 9;
printf(&quot;sum(%d ~ %d): %d\n&quot;,left, right, query(3, 9));
update(5, 5);
printf(&quot;sum(%d ~ %d): %d\n&quot;,left, right, query(3, 9));
return 0;</code></pre><p>}</p>
<pre><code>### 방법 2: 노드마다 구간 적기
```cpp
#include &lt;stdio.h&gt;
#include &lt;cmath&gt;
#include &lt;vector&gt;
using namespace std;
#define MAXN 100001
int src[MAXN];
/*
segment tree
    - 크기: 4*N, 2*N
    - 높이: ceiling(log2(N))
    - len : 1 &lt;&lt; (h+1)
*/
int segTree[4 * MAXN]; //주로 4 곱해서 사용

//vector&lt;int&gt; src;
//vector&lt;int&gt; segTree;

int N;
//node마다 어떤 구간인지 알아야 하는 경우
//init
int init(int node, int start, int end) {
    //leaf node인 경우
    if (start == end) {
        return segTree[node] = src[start];
    }
    int mid = (start + end) / 2;
    int leftNode = node &lt;&lt; 1; //node *2
    return segTree[node] = init(leftNode, start, mid) + init(leftNode+1, mid + 1, end);
}

//update: 해당 index의 값을 diff만큼 더하고 싶다.
void update(int node, int start, int end, int idx, int diff) {
    //범위 벗어나는 경우 pass
    if (idx &lt; start || end &lt; idx) return;

    segTree[node] += diff;
    //단말노드가 아니라면, 밑에 자식들까지 update 해줘야함.
    if (start != end) {
        int mid = (start + end) / 2;
        int leftNode = node &lt;&lt; 1;
        update(leftNode, start, mid, idx, diff);
        update(leftNode + 1, mid + 1, end, idx, diff);
    }
}
//sum: [left, right] 구간의 합을 알고싶다.
int sum (int node, int start, int end, int left, int right) {
    //1. 해당 노드의 구간이 모두 벗어나는 경우
    if (right &lt; start || end &lt; left) return 0;
    //2. 해당 노드의 구간이 모두 포함되는 경우
    else if (left &lt;= start &amp;&amp; end &lt;= right) {
        return segTree[node];
    }
    //3. 해당 노드의 구간이 포함하는 경우(관련 없는 구간 존재)
    //4. 해당 노드의 구간이 일부만 포함(관련 없는 구간 존재)
    int mid = (start + end) / 2;
    int leftNode = node &lt;&lt; 1;
    return sum(leftNode, start, mid, left, right) + sum(leftNode + 1, mid + 1, end, left, right);

}

int main() {
    N = 10;
    //src.clear();
    //src.resize(N+1);
    //segTree.clear();
    //int h = ceil(log2(N));
    //segTree.resize((h+1) &gt;&gt;1);
    //segTree.resize(N * 4);
    for (int i = 1; i &lt;= N; ++i) {
        src[i] = i;
    }
    init(1, 1, N); //root node부터 초기화

    int left = 3; int right = 9;
    printf(&quot;sum(%d ~ %d ): %d\n&quot;, left, right, sum(1, 1, N, left, right));

    update(1, 1, N, 5, 5);
    printf(&quot;sum(%d ~ %d ): %d\n&quot;, left, right, sum(1, 1, N, left, right));
    return 0;
}</code></pre><hr>
<h2 id="fenwick-treebinary-index-tree">Fenwick Tree(Binary Index Tree)</h2>
<p>: 연속된 구간합 빠르게 구하기</p>
<ul>
<li><p>항상 원소는 1부터!!!</p>
</li>
<li><p>자료구조 크기는 FenwickTree[src개수] -&gt; O(n)</p>
</li>
<li><p>Full binary tree(Segment tree의 진화형)</p>
</li>
<li><p>구간합 rangesum[i,j] = psum[0,j] - psum[0, i-1]</p>
</li>
<li><p>부분합 psum[0, j] = a[0] + a[1] ...</p>
</li>
<li><p>2의 승수 k : FenwickTree[k] = psum[1, k]</p>
</li>
<li><p>홀수 k : FenwickTree[k] = A[k]</p>
</li>
<li><p>그 외 k : FenwickTree[k] = A[k-1] + A[k]</p>
</li>
<li><p>idx = idx + (idx &amp; -idx) //뒤로 업데이트 해야하는 idx(증가)</p>
</li>
<li><p>idx = idx - (idx &amp; -idx) //앞으로 업데이트 해야하는 idx (감소)</p>
</li>
</ul>
<h3 id="연산">연산</h3>
<h4 id="updatepos-val">update(pos, val)</h4>
<p>: pos위치에 val 값 업데이트 </p>
<pre><code class="language-cpp">while(pos &lt;= NMAX){
    FenwickTree[pos] += val;
    pos += (pos &amp; -pos);
}</code></pre>
<h4 id="sumr">sum(r)</h4>
<pre><code class="language-cpp">int sum = 0;
while(pos &lt;= NMAX) {
    sum += Fenwick[pos];
    pos -= (pos &amp; -pos);
}</code></pre>
<p>x &amp; -x : x의 마지막 1 비트 추출
x - (x&amp;-x): x의 마지막 1부트 제거 </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[day8] Graph]]></title>
            <link>https://velog.io/@na_itsso/day8-Graph</link>
            <guid>https://velog.io/@na_itsso/day8-Graph</guid>
            <pubDate>Thu, 13 Mar 2025 06:55:58 GMT</pubDate>
            <description><![CDATA[<h2 id="그래프-종류">그래프 종류</h2>
<ul>
<li><p>무향 그래프</p>
</li>
<li><p>유향 그래프</p>
</li>
<li><p>가중치 그래프</p>
</li>
<li><p>사이클 없는 방향 그래프 (DAG)
(사이클: 두개 이상의 노드를 거쳐서 되돌아 올 수 있는 구조)</p>
<ul>
<li>위상정렬 문제</li>
<li>최장거리 구하기 : 가중치에 음수로 바꿔서 최단거리 문제(다익스트라) 로 구하기</li>
</ul>
<ul>
<li>완전 그래프: 정점들에 대해 가능한 모든 간선들을 가진 그래프(간선 개수= nC2)<h2 id="그래프-표현">그래프 표현</h2>
<h3 id="인접-행렬">인접 행렬</h3>
100만 * 100만 = 1억 불가?</li>
</ul>
</li>
<li><p>무향그래프는 대각선 대칭</p>
</li>
<li><p>행 기준: A행 ~ A에서 나가는 정점(진출차수)</p>
</li>
<li><p>열 기준: A열 ~ A로 들어오는 정점(진입차수)</p>
<h3 id="인접리스트">인접리스트</h3>
<p>vector&lt;vector&lt;&gt;&gt; : 일단 출발점으로부터 연결되는 것들만 
노드 번호가 10, 100만개이면 일차원 배열 형태로 잡는다.
가중치가 들어온다면, </p>
<h3 id="간선-배열">간선 배열</h3>
<p>만약에 노드 개수가 10억개 이상이면, map 구조로 만듣다.
map&lt;노드번호, vector&lt;pair&lt;&gt;&gt;&gt; </p>
</li>
</ul>
<p>노드개수 1000개 이하
2차원 배열</p>
<p>노드개수
2차원 벡터</p>
<p>노드 개수가 10억이면
map&lt;int, vector&gt;&gt; </p>
<h2 id="깊이우선탐색dfs">깊이우선탐색(dfs)</h2>
<p>선형구조: 순차 / 이진(sort 되어 있어야함)
비선형구조: bfs/dfs</p>
<p>노드 번호 주로 1부터 </p>
<p>stack<int> 
방문 유무 vt[]
stack 들어오면서 check: 절대 두번 들어오지 않음</p>
<ol>
<li>출발점을 stack이나 queue에 넣기</li>
<li>무한루프(!stack.empty) : 연결되어 있고 사용하지 않은것들만 stack에 push
stack 빠져가면서 check</li>
</ol>
<h2 id="너비우선탐색-bfs">너비우선탐색 (bfs)</h2>
<hr>
<h2 id="배열기반-코드">배열기반 코드</h2>
<pre><code class="language-cpp">
#include &lt;vector&gt;
#include &lt;stdio.h&gt;
#include &lt;iostream&gt;
#include &lt;stack&gt;
#include &lt;queue&gt;
#define MAXN 1001
using namespace std;
int V, E;
int g[MAXN][MAXN];
void bfs(int start) {
    //visited input할 때 check
    queue&lt;int&gt; q; //노드 번호 저장
    vector&lt;int&gt; vt(V + 1); //true,false보다 int가 더빠르다.

    q.emplace(start);
    vt[start] = 1; //들어가면서 방문 선언!
    printf(&quot;[&quot;);
    while (!q.empty()) {
        int u = q.front(); s.pop();
        //u로부터 연결되어 있고, 사용하지 않은
        for (int i = 1; i &lt;= V; ++i) {
            if (g[u][i] &amp;&amp; !vt[i]) {
                vt[i] = 1;
                q.emplace(i);
            }
        }
        printf(&quot;%d &quot;, u);
    }
    puts(&quot;]&quot;);
}
void dfs1(int start) {
    //visited input할 때 check
    stack&lt;int&gt; s; //노드 번호 저장
    vector&lt;int&gt; vt(V+1); //true,false보다 int가 더빠르다.

    s.emplace(start);
    vt[start] = 1; //들어가면서 방문 선언!
    printf(&quot;[&quot;);
    while (!s.empty()) {
        int u = s.top(); s.pop();
        //u로부터 연결되어 있고, 사용하지 않은
        for (int i = 1; i &lt;= V; ++i) {
            if (g[u][i] &amp;&amp; !vt[i]) {
                vt[i] = 1;
                s.emplace(i);
            }
        }
        printf(&quot;%d &quot;, u);
    }
    puts(&quot;]&quot;);
}
void dfs2(int start) {
    //visited input할 때 check
    stack&lt;int&gt; s; //노드 번호 저장
    vector&lt;int&gt; vt(V + 1); //true,false보다 int가 더빠르다.

    s.emplace(start);

    printf(&quot;[&quot;);
    while (!s.empty()) {
        int u = s.top(); s.pop();
        //나올때 체크하는 방식이므로 stack에 두번 들어갈 수 있다.
        if (vt[u]) continue; //사용했으면 continue;

        vt[u] = 1; //나올때 방문 선언!
        //u로부터 연결되어 있고, 사용하지 않은
        for (int i = 1; i &lt;= V; ++i) {
            if (g[u][i] &amp;&amp; !vt[i]) {
                //vt[i] = 1;
                s.emplace(i);
            }
        }
        printf(&quot;%d &quot;, u);
    }
    puts(&quot;]&quot;);
}

int vt[MAXN];
//깊이 우선 탐색을 재귀로 돌린 것 : backtracking
int dfs_rec(int start) {
    cout &lt;&lt; start;
    vt[start] = 1;
    for (int i = 1; i &lt;= V; ++i) {
        if (!vt[i] &amp;&amp; g[start][i]) {
            dfs_rec(i);
        }
    }
}
int main() {
    int sn, en;

    freopen(&quot;input.txt&quot;, &quot;r&quot;, stdin);
    scanf(&quot;&amp;d %d&quot;, &amp;V, &amp;E);
    for(int i = 0 ; i &lt; E ;++i){
        scanf(&quot;%d %d&quot;, &amp;sn, &amp;en);
        g[sn][en] = 1;
        g[en][sn] = 1;
    }
    return 0;
}
                         ```

</code></pre>
<p>unordered_map 사용</p>
<pre><code class="language-cpp">#include &lt;vector&gt;
#include &lt;stdio.h&gt;
#include &lt;iostream&gt;
#include &lt;stack&gt;
#include &lt;queue&gt;
#include &lt;unordered_map&gt;
#define MAXN 1001
using namespace std;
int V, E;
vector&lt;vector&lt;int&gt;&gt;g;
//unordered map : 십만개 - 우리가 아는 hash
unordered_map&lt;int, vector&lt;int&gt;&gt; gg;
void dfs(int start) {
    stack&lt;int&gt; s;
    vector&lt;int&gt; vt(V + 1);

    s.emplace(start);
    vt[start] = 1;
    printf(&quot;dfs: &quot;);
    while(!s.empty()){
        int u = s.top(); s.pop();
        for (int&amp; t : g[u]) {
            if (vt[t]) continue;
            s.emplace(t);
            vt[t] = 1;
        }
    }
}
int main() {
    int sn, en;

    freopen(&quot;input.txt&quot;, &quot;r&quot;, stdin);
    scanf(&quot;&amp;d %d&quot;, &amp;V, &amp;E);
    g.clear();
    g.resize(V + 1);
    for(int i = 0 ; i &lt; E ;++i){
        scanf(&quot;%d %d&quot;, &amp;sn, &amp;en);
        g[sn].emplace_back(en);
        g[en].emplace_back(sn);
        gg[sn].emplace_back(en);
        gg[en].emplace_back(sn);
    }
    for (int i = 1; i &lt;= V; ++i) {
        cout &lt;&lt; i &lt;&lt; &quot; : &quot;;
        for (int t : gg[i]) {
            cout &lt;&lt; t &lt;&lt; &quot; &quot;;
        }cout &lt;&lt; &quot;\n&quot;;
    }

    return 0;
}</code></pre>
<pre><code class="language-cpp">  /*
7 14
1 2 3
1 3 5
2 3 1
2 4 2
2 5 4
3 2 3
3 4 4
3 6 6
4 5 7
4 6 2
5 6 4
5 7 5
6 5 3
6 7 8
*/
#include&lt;stdio.h&gt;
#include &lt;queue&gt;
#include &lt;vector&gt;
using namespace std;
vector&lt;vector&lt;pair&lt;int,int&gt;&gt;&gt; g;
//무향그래프
int V;

void bfs(int start) {
    //visit input check
    queue&lt;int&gt; q;
    vector&lt;int&gt; dist(V + 1, INT_MAX);
    vector&lt;int&gt; p(V + 1);
    dist[start] = 0;

    q.emplace(start);

    while (!q.empty()) {
        int u = q.front(); q.pop();

        for (auto&amp; t : g[u]) {
            if (dist[t.first] &gt; dist[u] + t.second) {
                dist[t.first] = dist[u] + t.second;
                q.emplace(t.first);
                p[t.first] = u;
            }
        }
    }

    printf(&quot;idx\t:\t[&quot;);
    for (int i = 1; i &lt;= V; ++i) {
        printf(&quot;%d &quot;, i);
    }puts(&quot;]&quot;);

    printf(&quot;dist\t:\t[&quot;);
    for (int i = 1; i &lt;= V; ++i) {
        printf(&quot;%d &quot;, dist[i]);
    }puts(&quot;]&quot;);
    printf(&quot;p\t:\t[&quot;);
    for (int i = 1; i &lt;= V; ++i) {
        printf(&quot;%d &quot;, p[i]);
    }puts(&quot;]&quot;);
}

int main() {
    freopen(&quot;input.txt&quot;, &quot;r&quot;, stdin);
    int E;
    int sn, en, val;
    scanf(&quot;%d %d&quot;, &amp;V, &amp;E);
    g.clear();
    g.resize(V + 1);
    //pair f:nodeNum, s : time
    for (int i = 0; i &lt; E; ++i) {
        scanf(&quot;%d %d %d&quot;, &amp;sn, &amp;en, &amp;val);
        g[sn].emplace_back(en, val);
    }

#if 0
    for (int i = 1; i &lt;= V; ++i) {
        printf(&quot;%d : &quot;, i);
        for (auto&amp; t : g[i]) {
            printf(&quot;(%d,%d) &quot;, t.first, t.second);
        }
        puts(&quot;&quot;);
    }
#endif
    bfs(1);

    return 0;
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[day7] 문자열]]></title>
            <link>https://velog.io/@na_itsso/day7-%EB%AC%B8%EC%9E%90%EC%97%B4</link>
            <guid>https://velog.io/@na_itsso/day7-%EB%AC%B8%EC%9E%90%EC%97%B4</guid>
            <pubDate>Wed, 12 Mar 2025 02:50:00 GMT</pubDate>
            <description><![CDATA[<p>아스키 코드 (7bit)
&#39;0&#39; : 48
&#39;A&#39; : 65
&#39;a&#39; : 97
&#39;\n&#39;: 10
&#39;\r&#39;:</p>
<p>문자 0을 기준으로 적으면 연산자, 크면 숫자로 인식</p>
<p>한글 한자
euc.kr - 2byte
utf - 3byte</p>
<p>c</p>
<ul>
<li>배열 : 마지막에 <strong>구분자</strong> &#39;\0&#39; 방식
cpp : string</li>
<li>객체 : <strong>길이</strong> 방식(start로부터 얼마나)</li>
</ul>
<p>c계열: 컴파일러가 2바이트씩 읽어서 알아서 잘 해준다.</p>
<p>문자열 관련 headers
#include <string> : cpp string 객체
#include &lt;string.h&gt; : c의 string</p>
<p>atoi(문자열), atof: 표준함수
itoa: 비표준 리눅스, gcc에는 없음.</p>
<pre><code class="language-cpp">
  #include &lt;stdio.h&gt;
//#include &lt;string.h&gt; // c 기반 문장려 : strlen 
#include &lt;cstring&gt; // string.h 확장버전
#include &lt;cstdlib&gt; //atoi, itoa(숫자 &lt;-&gt; 문자)
#include &lt;iostream&gt;
using namespace std;
int my_strlen(char* str) { //c는 1byte를 len 1로 생각(한글은 2byte)
    int len = 0;
    while (*str) { //현재 값을 찍을 때 * 사용, 마지막 문
        len++;
    }
    return len;
}
//long long - 64bit
//8, 10, 16 진법이 아닌 경우
void my_itoa(char* sNum, int val, int digit) {
    int idx = 0;
    if (val &lt; 0) {
        sNum[0] = &#39;-&#39;;
        idx++;
    }
    int iNum; char c;
    while (val) {
        iNum = iNum % digit;
        if (iNum &lt; 10) { //0~9까지의 형태가 들어옴
            c = iNum + &#39;0&#39;;
        }
        else {
            c = iNum + &#39;a&#39; - 10;
        }
        char c = val % 10 + &#39;0&#39;;
        sNum[idx++] = c;
        val = val / 10;
    }
    sNum[idx] = 0; //널문자 넣어주기
    //puts(sNum);
    //순서 반대로 바꿔줘야함(reverse)
    int len = idx / 2; //ex) len 4 -&gt; 중앙 2 len 5 -&gt; 중앙 2
    for (int i = 0; i &lt; len; ++i) {
        char t = sNum[i];
        sNum[i] = sNum[idx - 1 -i]; //0번과 3번이랑 바꾸기
        sNum[idx - 1 - i] = t;
    }
}
void my_strcpy(char* dest, char* src) {
    while (*dest++ = *src++); //주소 복사시키고 ++로 이동
}
int main() {
    char buf3[100] = &quot;123&quot;;
    char buf4[100];
    int iNum; double dNum = 1.234567;
    //scanf(&quot;%d&quot;, &amp;iNum); //키보드로부터 읽어라
    sscanf(buf3, &quot;%d&quot;, &amp;iNum ); //배열로부터 읽어라
    cout &lt;&lt; &quot;iNum: &quot; &lt;&lt; iNum &lt;&lt; &quot;\n&quot;;
    sprintf(buf4, &quot;%o&quot;, iNum); //배열에다가 뿌려라.
    puts(buf4);
    sprintf(buf4, &quot;%x&quot;, iNum); //배열에다가 뿌려라.
    puts(buf4);
    sprintf(buf4, &quot;%lf&quot;, dNum); //배열에다가 뿌려라.
    puts(buf4);
    char sNum[] = &quot;123a&quot;;
    //숫자형 문자열 -&gt; 숫자
    iNum = atoi(sNum); //&quot;123&quot;만 들어옴. 
    char buf2[100];
    itoa(iNum, buf2, 2);
    puts(buf2);

    char s[] = &quot;hong&quot;;
    //string.h
    char s1[11] = &quot;hong&quot;;
    char s2[11] = &quot;aong&quot;;
    printf(&quot;len: %d\n&quot;, strlen(s1));
    //(a-b) &gt; 0 : 1 : 앞선 문자열이 더 크다  / 0: 같다 / -1 : 뒤 문자열이 더 크다.
    printf(&quot;cmp: % d\n&quot;, strcmp(s2, s1));

    char buf[100] = &quot;hong&quot;;
    //buf = s2 ; //error! (왜냐하면 buf는 배열이므로 주소를 바꿀 수 없음)
    strcpy(buf, s2); //초기화 다음 단계에서 어떤 문자열을 복사하려면 strcpy 사용해야함.
    strcat(buf, s2); //문자열 더하기

    char str1[11] = &quot;hong&quot;; //배열(배열 주소를 바꿀 수 없음: 상수)
    //char str2[11] = { &#39;h&#39;, &#39;o&#39;, &#39;n&#39;, &#39;g&#39; };
    char str2[11]; 
    const char* str3 = &quot;hong&quot;; //포인터로 선언? 근데 이건 const이면,,, 바꿀 수없는거아님??

    str2[0] = &#39;h&#39;;
    str2[1] = &#39;o&#39;;
    str2[2] = &#39;\0&#39;; 
    printf(&quot;%s\n&quot;, str1);
    puts(str3);
    /*
        배열 
        - str1 = str2
        포인터는 자료형 동일하면 가능
        - str3 = str2 
    */
    return 0;
}</code></pre>
<hr>
<pre><code class="language-cpp">#include &lt;stdio.h&gt;
#include &lt;string&gt;
#include &lt;iostream&gt; //cin, cout

using namespace std;

int main() {
    string str;
    cin &gt;&gt; str;
    cout &lt;&lt; &quot;str: &quot; &lt;&lt; str &lt;&lt; endl;

    //file 종류 지점: -1로 끝남(EOF)
    while (getchar() != 10); //10 : &#39;\n&#39; 개행 (input 버퍼 비우는 코드)(실무에서)
    getline(cin, str);//현위치부터 개행 진적까지 모든 문자열 받기
    //c: gets , cpp: getline  -&gt; buffer 비우기 작업 필요? 출력문 버퍼 비우기 (fflush) 
    cout &lt;&lt; &quot;str: &quot; &lt;&lt; str &lt;&lt; endl;
    return 0;
}</code></pre>
<pre><code class="language-cpp">#include &lt;stdio.h&gt;
#include &lt;string&gt;
#include &lt;iostream&gt; //cin, cout

using namespace std;

int main() {
    string s = &quot;abcdefghij&quot;;

    //string -&gt; arry
    char str[] = &quot;hong&quot;;

    string str1 = &quot;hong&quot;;
    string str2(&quot;hong&quot;);
    string str3 = str1; //기존 문자열 대입도 가능
    string str4 = str; //배열구조 넘겨주면 string으로 바뀜 
    //나중에 배열로 사용하고 싶으면 string.c_str() 사용
    string str5(str);


    char buf[100];
    strcpy(buf, str1.c_str());
    printf(&quot;str: %s\n&quot;, str); //ok
    //printf(&quot;str1: %s\n&quot;, str1);//error!
    printf(&quot;str1 : %s\n&quot;, str1.c_str()); // string에서 c 기반 배열주소로 사용하고 싶을때
    cout &lt;&lt; &quot;str : &quot; &lt;&lt; str &lt;&lt; endl;
    cout &lt;&lt; &quot;str1 : &quot; &lt;&lt; str1 &lt;&lt; endl;
}</code></pre>
<pre><code class="language-cpp">  #include &lt;stdio.h&gt;
#include &lt;string&gt;
#include &lt;iostream&gt; //cin, cout

using namespace std;

int main() {
    string str = &quot;abcdefghijde&quot;;
    printf(&quot;str[1]: %c\n&quot;, str[1]); //이게 더 속도 빠름
    printf(&quot;str[1]: %c\n&quot;, str.at(1));
    int idx = str.find(&quot;de&quot;); //0번째 부터 &quot;de&quot;가 나타나는 첫번째 위치를 알려줌.
    printf(&quot;idx : %d\n&quot;, idx);
    idx = str.find(&quot;de&quot;, 5); //5번째 부터 &quot;de&quot;가 나타나는 첫번째 위치를 알려줌.
    printf(&quot;idx : %d\n&quot;, idx);
    //값이 존재하지 않으면 -1 반환
    idx = str.rfind(&quot;de&quot;); //n-1번째부터 거꾸로 찾기
    printf(&quot;idx : %d\n&quot;, idx, 5);//5번째부터 에서 거꾸로 찾기

}</code></pre>
<pre><code class="language-cpp">#include &lt;stdio.h&gt;
#include &lt;string&gt;
#include &lt;iostream&gt; //cin, cout
#include &lt;vector&gt;

using namespace std;

int main() {
    //: 기준으로 split하기
    vector&lt;int&gt; idxs;
    string str = &quot;aaa:bbb:ccc:ddd&quot;;
    int idx = 0;

    while (1) {
        idx = str.find(&quot;:&quot;, idx);
        if (idx == -1) {
            break;
        }
        idxs.emplace_back(idx);
        idx++;
    }
    for (int&amp; i : idxs) {
        printf(&quot;%d &quot;, i);
    }puts(&quot;&quot;);

    string subString = str.substr(4); //이 5번(idx)부터 끝까지
    cout &lt;&lt; subString &lt;&lt; endl;
    subString = str.substr(4,3); //이 5번(idx)부터 3(크기)
    cout &lt;&lt; subString &lt;&lt; endl;
    subString = str.substr(4, 10000); //크기 초과해도 오류 안남
    cout &lt;&lt; subString &lt;&lt; endl;

}</code></pre>
<p>cpp 에는 string reverse함수가 없다!
string +operator가 만들어져 있으므로 string 더하기 가능!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[day7] stack, queue]]></title>
            <link>https://velog.io/@na_itsso/day7-stack-queue</link>
            <guid>https://velog.io/@na_itsso/day7-stack-queue</guid>
            <pubDate>Wed, 12 Mar 2025 01:06:49 GMT</pubDate>
            <description><![CDATA[<h2 id="stack">stack</h2>
<p>1) 괄호 검사</p>
<p>2) 문자열 계산기
sol1 - stack
중위 표현식 -&gt; 후위 표현식으로 바꾸기
ex) a - b =&gt; a b -</p>
<p>stack : 나보다 서열이 낮을 때 까지 빼기</p>
<p>후위 문자열 배열: 피연산자 들어오기</p>
<p>so2 - 이진트리</p>
<p>3) dfs : 모든 경우의 수 - stack
bfs : 단계별 검증 / 최단 경로 - queue</p>
<hr>
<h2 id="queue">queue</h2>
<h3 id="원형큐">원형큐</h3>
<p>queue는 front에서 삭제하는 구조이므로, 선형큐으로 했을 때 메모리 부족 문제 발생 가능 =&gt; 실무에서 직접 구현할 땐 <strong>&quot;원형큐&quot;</strong>를 사용한다.</p>
<p>초기상태 : front = rear = 0
공백상태 : front = rear</p>
<p>6개 크기 -&gt; 5개 자료 보관
rear = (r + 1) % N
front = (f + 1) % N
(rear+1) % n = front 이면, 다 찬 경우</p>
<h3 id="연결큐">연결큐</h3>
]]></description>
        </item>
        <item>
            <title><![CDATA[[SWEA] 1266. 소수 완제품 확률]]></title>
            <link>https://velog.io/@na_itsso/1266.-%EC%86%8C%EC%88%98-%EC%99%84%EC%A0%9C%ED%92%88-%ED%99%95%EB%A5%A0</link>
            <guid>https://velog.io/@na_itsso/1266.-%EC%86%8C%EC%88%98-%EC%99%84%EC%A0%9C%ED%92%88-%ED%99%95%EB%A5%A0</guid>
            <pubDate>Wed, 12 Mar 2025 00:02:15 GMT</pubDate>
            <description><![CDATA[<p>1) 1 - (1 - A 성공) * ( 1 - B 성공))</p>
<p>2) n번 독립시행확률: 
nCr * (성공확률)^r * (1-성공확률)^(n-r)</p>
<p>3) dp
4) %f: 여섯번째자리까지 = %.6f
<strong>cout은 안됨</strong></p>
<pre><code class="language-cpp">/*
5분에 하나의 가구
완제품: 결함X
두명 가구 장인 시합
각 장인 완제품 개수: 소수개수 인가

pa = (5분안 완제품 만들 확률)
pb = (5분안 완제품 만들 확률)

총 시간 90분 = 최소 2개 최대 36개
한 장인: 최소 0개 최대 18개
n: 18번 시도 , r: (0~18)중 소수가 아닌 수

적어도 둘 중 한명이라도 소수개 만들 확률 = 1 - (둘다 소수가 아닐 확률)

장인a: 18Cr * (pa)^r * (1-pa)^(18 - r)
장인b: 18Cr * (pb)^r * (1-pb)^(18 - r)
*/
#include&lt;iostream&gt;
#include&lt;vector&gt;
#include&lt;algorithm&gt;
#include&lt;math.h&gt;
#define NMAX 11
#define diff (1e-12)
using namespace std;
double pa; double pb;
vector&lt;int&gt; numbers = { 0, 1, 4, 6, 8, 9, 10, 12, 14, 15, 16, 18 };
int dp[19][19];
vector&lt;int&gt; comb(19);

int comb_cal(int n, int r) {
    if (r == 0 || n == r) return 1;
    //0이면
    if (!dp[n][r]) return dp[n][r] = comb_cal(n - 1, r) + comb_cal(n - 1, r - 1);
    return dp[n][r];
}
int main(int argc, char** argv)
{
    int test_case;
    int T;
    //freopen(&quot;input.txt&quot;, &quot;r&quot;, stdin);
    cin &gt;&gt; T;

    //조합: 18C숫자 계산 미리 해두기
    for (int&amp; r : numbers) {
        comb[r] = (comb_cal(18, r));
        //cout &lt;&lt; comb[r] &lt;&lt; endl;
    }
    for (test_case = 1; test_case &lt;= T; ++test_case)
    {
        int a, b;
        cin &gt;&gt; a &gt;&gt; b;
        cout &lt;&lt; &quot;#&quot; &lt;&lt; test_case &lt;&lt; &quot; &quot;;
        if ((!a) &amp;&amp; (!b)) {
            printf(&quot;%.6lf\n&quot;, 0.0);
            continue;
        }
        pa = (double)a / 100; pb = (double)b / 100;
        double sum_a = 0;
        double sum_b = 0; 
        //cout &lt;&lt; &quot;pa: &quot; &lt;&lt; pa &lt;&lt; &quot; pb: &quot; &lt;&lt; pb &lt;&lt; endl;
        if (pa == 0) {
            for (int&amp; r : numbers) {

                sum_b += (comb[r] * pow(pb, r) * pow((1-pb), (18 - r)));
            }
            printf(&quot;%.6lf\n&quot;, (1 -  sum_b));
            continue;
        }
        else if (pb == 0) {
            for (int&amp; r : numbers) {
                sum_a += (comb[r] * pow(pa, r) * pow((1-pa), (18 - r)));
            }
            printf(&quot;%.6lf\n&quot;, (1 - sum_a));
            continue;
        }
        else {
            for (int&amp; r : numbers) {
                //cout &lt;&lt; (comb[r] * (float)pow(pb, r) * (float)pow((1-pb), (18 - r))) &lt;&lt; endl;
                sum_a += (comb[r] * (float)pow(pa, r) * (float)pow((1-pa), (18 - r)));
                sum_b += (comb[r] * (float)pow(pb, r) * (float)pow((1-pb), (18 - r)));
            }
            printf(&quot;%.6lf\n&quot;, (1 - (sum_a * sum_b)));
        }


    }
    return 0;//정상종료시 반드시 0을 리턴해야합니다.
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[day6] TSP]]></title>
            <link>https://velog.io/@na_itsso/day6-TSP</link>
            <guid>https://velog.io/@na_itsso/day6-TSP</guid>
            <pubDate>Tue, 11 Mar 2025 04:17:31 GMT</pubDate>
            <description><![CDATA[<h2 id="tsp">TSP</h2>
<p>입력값의 개수에 따라 달라짐.</p>
<h3 id="1-출발-도착-선택-모든-도시-여행">1) 출발, 도착 선택, 모든 도시 여행</h3>
<h3 id="2-3곳만-숙박비-선택비용이-가장-적은-세개-구하기">2) 3곳만 숙박비 선택(비용이 가장 적은 세개 구하기)</h3>
<p>6C3 중 비용합 최소</p>
<h3 id="3-여행자-경비-한정적-최대-개수-도시">3) 여행자 경비 한정적, 최대 개수 도시?</h3>
]]></description>
        </item>
        <item>
            <title><![CDATA[[day6] 순열, 조합]]></title>
            <link>https://velog.io/@na_itsso/day6-%EC%88%9C%EC%97%B4-%EC%A1%B0%ED%95%A9</link>
            <guid>https://velog.io/@na_itsso/day6-%EC%88%9C%EC%97%B4-%EC%A1%B0%ED%95%A9</guid>
            <pubDate>Tue, 11 Mar 2025 04:11:39 GMT</pubDate>
            <description><![CDATA[<pre><code class="language-cpp">#include&lt;iostream&gt;
#include&lt;algorithm&gt;
#define MAX 51
//세줄짜리는 중괄호 필요
#define MYSWAP (a,b) {int t = a ; a = b ; b = t;}
int N;
int R;
using namespace std;
//tc마다 for가 유동적으로 바뀌어지는 경우 : 재귀 사용
/*
&lt;재귀&gt;
1. 탈출조건
2. 탈출 하지 않을 때 어떤 수식

&lt;중복x순열&gt;
- n-&gt; n-1 , r -&gt; r-1
- 뽑아야하는 대상이 r보다 크다 (n&gt;=r)
- 1씩 줄여줄여나갔을 때, r이 0 되면, 탈출
*/
//char src[MAX] = { &#39;a&#39;, 98, 99 }; //마지막 위치 일단 후보
char src[MAX] = { 0, &#39;a&#39;, &#39;b&#39;, &#39;c&#39; };
char temp[MAX];//현재 선택 보관
void print() {
    printf(&quot;[&quot;);
    for (int i = 0; i &lt; R; ++i) {
        printf(&quot;%c &quot;, temp[i]);
    }puts(&quot;]&quot;);
}
#if 0
inline void MY_SWAP(char* a, char* b) { //포인터 개념
    int t = *a;
    *a = *b;
    *b = t;
}
inline void MY_SWAP2(char&amp; a, char&amp; b) {
    int t = a;
    a = b;
    b = t;
}
//nPr
void perm1(int n, int r) {
    //n&gt;=r
    if (r == 0) {
        return;
    }
    //마지막 위치 (n-1) , 2, 1, 0 돈다.
    for (int i = n - 1; i &gt;= 0; --i) {
        //현재 위치 선택 후 줄여나가기
        //swap
        int t = src[n - 1];
        src[n - 1] = src[i];
        src[i] = t;


        temp[r-1] = src[n - 1];
        perm1(n - 1, r - 1);

        //되돌려놓기
        t = src[n - 1];
        src[n - 1] = src[i];
        src[i] = t;
    }
}

void perm2(int n, int r) {
    //n&gt;=r
    if (r == 0) {
        return;
    }
    //마지막 위치 (n-1) , 2, 1, 0 돈다.
    for (int i = n - 1; i &gt;= 0; --i) {
        //현재 위치 선택 후 줄여나가기
        //MYSWAP(src[n-1], src[i]);
        //MY_SWAP(&amp;src[n - 1], &amp;src[i]);
        //MY_SWAP(src[n-1], src[i]; -&gt; 참조자 inline함수
        swap(src[n - 1], src[i]);


        temp[r - 1] = src[n - 1];
        perm2(n - 1, r - 1);

        //되돌려놓기
        //MYSWAP(src[n-1], src[i])
        MY_SWAP(&amp;src[n - 1], &amp;src[i]);
    }
}
#endif
void perm3(int n, int r) {
    if (r == 0) {
        print();
        return;
    }

    for (int i = n; i; --i) {
        swap(src[n], src[i]);

        temp[r - 1] = src[n];
        perm3(n - 1, r - 1);

        swap(src[n], src[i]);
    }
}
/*
    중복 순열: 직전에서 사용한 것, 또 사용 가능!
    n은 줄지 않음!(뽑는 대상 개수는 줄지 않는다.)
*/

void perm_not_dup(int n, int r) {
    if (r == 0) {
        print();
        return;
    }

    for (int i = n; i; --i) {
        swap(src[n], src[i]);

        temp[r - 1] = src[n];
        perm3(n, r - 1); //n-1 이 아닌 n으로 

        swap(src[n], src[i]);
    }
}

void pi(int n, int r) { //이거는 이상ㅎ...
    if (r == 0) {
        print();
        return;
    }

    for (int i = n; i; --i) {
        temp[r] = src[i];
        pi(n, r - 1);
    }
}

/*
    중복 x 조합
    1) 포함되는경우: n-1Cr-1
    2) 포함되지 않는 경우: n-1Cr

    포함되는 경우에서 일을 해야함.
*/

void comb(int n, int r) {

    if (r == 0) { //포함되는 경우 r이 계속 준다.
        print();
        return;
    }

    if (n &lt; r) {
        return;
    }
    temp[r] = src[n];
    comb(n - 1, r - 1); // 포함되는 경우
    comb(n - 1, r); //포함되지 않는경우
}
/*
    중복조합
*/
void H(int n, int r) {

    if (r == 0) { //포함되는 경우 r이 계속 준다.
        print();
        return;
    }

    if (n &lt; r) {
        return;
    }
    temp[r] = src[n];
    H(n, r - 1); // 포함되는 경우, 재사용 가능
    H(n - 1, r); //포함되지 않았으므로, n-1 유지
}
//nC0 = nCn = nP0 = 1
int comb_cal(int n, int r) { //계산값만 
    if (r == 0 || n == r) return 1; 
    //temp[r] = src[n];
    return comb_cal(n - 1, r - 1) + comb_cal (n - 1, r); 
}
//파스칼의 삼각형 - 이차원 배열
int dp[101][101];
int comb_cal_dp(int n, int r) {
    if (r == 0 || n == r) {
        return 1;
    }
    if (dp[n][r] == 0) {
        dp[n][r] = comb_cal_dp(n - 1, r - 1) + comb_cal_dp(n - 1, r);
    }
    else return dp[n][r];
}
//뽑는 개수가 2개이면, 이중 for문으로 다 해결 가능
//0번자리 안비워도 됨
void Ris2(int n, int r) {
    puts(&quot;중복순열: &quot;);
    //중복순열
    for (int i = 1; i &lt;= n; ++i) {
        for (int j = 1; j &lt;= n; ++j) {
            printf(&quot;[%c %c]\n&quot;, src[i], src[j]);
        }
    }
    puts(&quot;중복순열: &quot;);
    //중복X 순열
    for (int i = 1; i &lt;= n; ++i) {
        for (int j = 1; j &lt;= n; ++j) {
            if (i != j) {
                printf(&quot;[%c %c]\n&quot;, src[i], src[j]);
            }
        }
    }
    puts(&quot;조합: &quot;);
    //조합
    for (int i = 1; i &lt; n; ++i) {
        for (int j = 1+i; j &lt;= n; ++j) {
            if (i != j) {
                printf(&quot;[%c %c]\n&quot;, src[i], src[j]);
            }
        }
    }
    puts(&quot;중복조합: &quot;);
    //조합
    for (int i = 1; i &lt;= n; ++i) {
        for (int j = i; j &lt;= n; ++j) {
            printf(&quot;[%c %c]\n&quot;, src[i], src[j]);
        }
    }

}
int main(int argc, char** argv)
{
    N = 3;
    R = 2; 
    perm3(N, R);
    puts(&quot;===========&quot;);
    perm_not_dup(N, R);
    puts(&quot;===========&quot;);
    pi(N, R);
    puts(&quot;============&quot;);
    //부분집합 뽑기
    for (int i = 0; i &lt;= N; ++i) {
        R = i;
        comb(N, R);
    }
    puts(&quot;===============&quot;);
    N = 100, R = 2;
    cout &lt;&lt; comb_cal(N, R) &lt;&lt; endl;
    Ris2(3, 2);
    return 0;//정상종료시 반드시 0을 리턴해야합니다.

}


/*
회사 납품 최대-최소 가 최소
비정렬 데이터 들어옴 -&gt; 정렬시키기
해당 구간의 최대, 최소는 포함시키고, 해당 구간 내에서 몇개 순서없이 뽑기(조합)
nC3 + nC4 + ... nCn 구하기

nC0 + nC1 + ... + nCn = 2^n

Todo: 5C3 + 5C4 + 5C5 = 2^n - (nC0 + nC1 + nC2)


key는 lower_bound로 인덱스 찾고
k = start - end - 1 (구간 안 count)
*/

/*
baby-gin Game 
: 10장 중 임의로 6장 뽑았을때
- 연속된 번호 : run
- 똑같은 숫자 3개: triplet

how?
6! - 순열 
*/</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[day5] 반복과 재귀 호출(p.84)]]></title>
            <link>https://velog.io/@na_itsso/day5-%EB%B0%98%EB%B3%B5%EA%B3%BC-%EC%9E%AC%EA%B7%80-%ED%98%B8%EC%B6%9Cp.84</link>
            <guid>https://velog.io/@na_itsso/day5-%EB%B0%98%EB%B3%B5%EA%B3%BC-%EC%9E%AC%EA%B7%80-%ED%98%B8%EC%B6%9Cp.84</guid>
            <pubDate>Mon, 10 Mar 2025 10:49:12 GMT</pubDate>
            <description><![CDATA[<ol>
<li><strong>탐욕알고리즘</strong> (일부분 검증)</li>
<li>분할검증 (일부분 검증)</li>
<li>백트래킹(가지치기) (완전 검증) - ad 시험</li>
<li>동적프로그래밍(완전 검증) - pro 시험</li>
</ol>
<hr>
<p>dp : 반복문 vs 재귀호출
-&gt; 반복문 구조가 덜 메모리 사용하고, 더 빠르다.
-&gt; 그러나 tc마다 반복문 개수가 다를 때 재귀만 가능한 경우도 있다.</p>
<h2 id="재귀호출">재귀호출</h2>
<ul>
<li>stack 메모리 할당이 가능한 <strong>깊이</strong>를 확인 필요. (stack overflow)</li>
<li>탈출 조건, 유도된 수식</li>
<li></li>
</ul>
<h2 id="반복문">반복문</h2>
<ul>
<li>슬라이딩 윈도우(1억개 이상일 경우 메모리 초과 날 수 있음.)</li>
<li>피보나치: 모듈러 처리로 메모리 절약하는 방법.</li>
</ul>
<p>**피보나치라고 문제에 나와있지 않더라도, 수식을 세워보니(경우의 수 세었을 때) 피보나치 계열일 수 있음!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[day5] 탐욕 알고리즘]]></title>
            <link>https://velog.io/@na_itsso/day5-%ED%83%90%EC%9A%95-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98</link>
            <guid>https://velog.io/@na_itsso/day5-%ED%83%90%EC%9A%95-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98</guid>
            <pubDate>Mon, 10 Mar 2025 04:17:47 GMT</pubDate>
            <description><![CDATA[<p>생각이 나는대로 짜는 방식...</p>
<p>최적부분구조 : 해결한 부분은 되돌아보지 않는 구조
중복부분구조 : </p>
<p>그 부분에서 최적값이 한개가 나오는데, 합쳐놓고 보니 오답이 나오는 구조
-&gt; <del>탐욕알고리즘</del> 완전 탐색으로 해결해야 한다!
-&gt; 항상 증명을 해야하거나, 알고 있는 경우 (다익스트라 최단경로 알고리즘, Prim 알고리즘)</p>
<p>ex) 최소 신장트리(minimum spanning tree)</p>
<ul>
<li>prim 알고리즘
ex) aaaabbcaaaaddd -&gt; a4b2c1a4d3 run length 알고리즘?
ex) 허프만 코딩 : 빈도수가 가장 많이 나온 것을 가장 적은 byte ? 
-&gt; 허프만 트리</li>
</ul>
<p>ex) 거스름돈 문제: 돈의 관계가 배수 관계가 성립하면 탐욕 알고리즘이지만, 그게 아닌 경우는 완전탐색을 해야한다.
ex) 부정방정식(변수의 개수보다 방정식 개수가 적은 경우): 중복조합으로 짤 경우 시간이 너무 오래걸리므로 dp로 풀기</p>
<p>ex) knapsack
Todo: 가방이 감당할 수 있는 무게, 가격의 총합 max</p>
<p>1) zero one knapsack : 모든 경우의 수</p>
<ul>
<li><p>부분집합 이용해서 풀이(backtracking) or dp 알고리즘</p>
</li>
<li><p>종류: 보석의 개수가 무한개(동전알고리즘과 유사) / 한정적</p>
<pre><code class="language-cpp">#include &lt;iostream&gt;
#include &lt;stdio.h&gt;
#define MAXN 31
#define MAXW 1001
using namespace std;
//int j[][2] = { {0} , { 4, 40 }, {10, 50}, {20, 150} };
int jw[MAXN] = { 0, 4, 10, 20 };
int jp[MAXN] = { 0, 40, 50, 100 };
int N, W;
//knapsack1 - 보석이 무한개 : ans =&gt; 40 * 7
//중복해서 사용하는 경우 =&gt; 1차원 배열 dp
int dp1[MAXW];
int knapsack1() {
  for (int i = 1; i &lt;= W; ++i) { //경우 : 기준 가방
      for (int j = 1; j &lt;= N; ++j) { //검증 : 보석
          //i: 현재 가방 무게 , j: 새로 담을 보석
          if (i &gt;= jw[j]) {
              if (dp1[i] &lt; dp1[i - jw[i]] + jp[j]) {
                  dp1[i] = dp1[i-jw[i]] + jp[j];
              }
          }
      }
  }

  return dp1[W];
}
</code></pre>
</li>
</ul>
<p>//knapsack2 - 보석이 한개 : ans =&gt; 20 , 10kg: 200만원
//중복해서 사용 못하는 경우 =&gt; 2차원배열
int dp2[MAXN][MAXW]; //보석이 기준
int knapsack2() {
    for (int i = 1; i &lt;= N; ++i) { //경우 : 기준 보석
        for (int j = 1; j &lt;= W; ++j) { //검증 : 가방
            //i: 현재 보석 가격 , j: 새로 담을 보석
            dp2[i][j] = dp2[i - 1][j]; //복사시켜놔야 다음에 사용가능
            if (i &gt;= jw[j]) {
                if (dp2[i][j] &lt; dp2[i - 1][j - jw[i]] + jp[i]) {
                    //직전 데이터로부터 덜어내고
                    dp2[i][j] = dp2[i - 1][j - jw[i]] + jp[i];
                }
            }
        }
    }</p>
<pre><code>return dp2[N][W];</code></pre><p>}</p>
<p>int main(int argc, char** argv)
{
    W = 30; N = 3;</p>
<pre><code>return 0;//정상종료시 반드시 0을 리턴해야합니다.</code></pre><p>}</p>
<pre><code>
2) fraction knapsack : 탐욕 알고리즘


```cpp
#include &lt;iostream&gt;
#include &lt;stdio.h&gt;
#include &lt;algorithm&gt;
#define MAXN 31
#define MAXM 1001
int moneys[] = { 0, 1, 4, 6 };
int N; int MONEY;
using namespace std;

int dp[MAXM];
//최소 카운트를 세는 것! 
int getCnt() {
#if 0
    //최솟값 찾고 싶으므로, 무한대로 초기화
    for (int i = 1; i &lt;= MONEY; ++i) { //0번지에는 0이여야함?
        dp[i] = 0x7fffffff;
    }
#endif 
    fill(dp + 1, dp + MONEY + 1, 0x7fffffff);

    for (int i = 1; i &lt;= MONEY; ++i) {
        for (int j = 1; j &lt;= N; ++j) {
            if (i &gt;= moneys[j]) {
                if (dp[i] &gt; dp[i - moneys[j]] + 1) {
                    dp[i] = dp[i - moneys[j]] + 1;
                }
            }
        }
    }

    return dp[MONEY];
}


int main(int argc, char** argv)
{
    N = 3; //돈의 종류 개수
    MONEY = 8; //돌려받으려는 값

    return 0;//정상종료시 반드시 0을 리턴해야합니다.
}</code></pre><p>&lt;이미 만들어진 코드들, 문제를 읽고 해당 알고리즘인지 파악하고, 구현&gt;
TSP
LIS
LCS
MCM
동전
knapsack
피보나치</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[6484]]></title>
            <link>https://velog.io/@na_itsso/6484</link>
            <guid>https://velog.io/@na_itsso/6484</guid>
            <pubDate>Wed, 05 Mar 2025 08:39:33 GMT</pubDate>
            <description><![CDATA[<p>팩토리얼로 나타났을 때, 소인수분해하기</p>
<p>에라토스테네체의 체</p>
<ol>
<li>처음에 다 default true로 하기</li>
<li>i*i &lt; n 인 i 까지 반복(sqrt(N))</li>
<li>%i == 0 이면 false로 바꾸기</li>
</ol>
<p>현재 위치가 소수이면 primes vector 배열에 넣기
소수가 아닌 것들은 bool값 바꿔주기</p>
<p>10억 7은 int 안으로 들어올 수 있다.
그러나 곱하는 계산 과정 속에서 int 범위 넘을 수 있다.
long long으로 사용해줘야한다!</p>
<p>그릐고 n을 나는 임시 변수로 저장하지 않아서 값이 바뀌었다.
그래서 제대로 된 답이 나오지 않았다.
변수를 그대로 사용할 때 뒤에서 다시 사용하면, 해당 값을 임시변수에 저장하여 사용하는 습관을 기르자.</p>
<pre><code class="language-cpp">#include &lt;iostream&gt;
#include &lt;algorithm&gt;
#include &lt;unordered_map&gt;
#include &lt;vector&gt;

#define div (1000000007)
#define MAXN 100000
using namespace std;
bool isprime[MAXN + 1];
vector&lt;int&gt; primes;
int main(int argc, char** argv)
{
    int test_case;
    int T;
    freopen(&quot;input.txt&quot;, &quot;r&quot;, stdin);
    cin &gt;&gt; T;
    //소수 전처리
    for (int i = 0; i &lt;= MAXN; ++i) isprime[i] = 1; //모두 true로 초기화
    isprime[1] = false; isprime[0] = false;
    for (int i = 2; i * i &lt;= MAXN; i++) {
        if (!isprime[i]) continue; //소수가 아니면 pass
        for (int j = i * i; j &lt;= 100000; j += i) {
            isprime[j] = false;
        }
    }
    for (int i = 2; i &lt;= MAXN; ++i) {
        if (isprime[i]) {
            primes.push_back(i);
        }
    }
    for (test_case = 1; test_case &lt;= T; ++test_case)
    {
        int n, k;
        long long ans = 1;
        cin &gt;&gt; n &gt;&gt; k;
        //TODO: nCk 의 약수의 개수를 구하여라.
        //1. 소인수분해
        unordered_map &lt;int, int&gt; um; // 소수, 지수
        for (int prime : primes) {
            if (prime &gt; n) break;
            int factor_cnt = 0;
            //n!
            int temp_n = n;
            while (temp_n) {
                temp_n /= prime;
                factor_cnt += temp_n;
            }
            //k!
            int temp_k = k;
            while (temp_k) {
                temp_k /= prime;
                factor_cnt -= temp_k;
            }
            //(n-k)!
            int temp_nk = n - k;
            while (temp_nk) {
                temp_nk /= prime;
                factor_cnt -= temp_nk;
            }

            if (factor_cnt &gt; 0) {
                long long tmp = (factor_cnt + 1) % div;
                ans = (ans * tmp) % div;
            }
        }

        cout &lt;&lt; &quot;#&quot; &lt;&lt; test_case &lt;&lt; &quot; &quot; &lt;&lt; ans &lt;&lt; &quot;\n&quot;;
    }
    return 0;//정상종료시 반드시 0을 리턴해야합니다.
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Verilog: Procedure]]></title>
            <link>https://velog.io/@na_itsso/Verilog-Procedure</link>
            <guid>https://velog.io/@na_itsso/Verilog-Procedure</guid>
            <pubDate>Tue, 25 Feb 2025 07:36:05 GMT</pubDate>
            <description><![CDATA[<hr>
<h1 id="procedural-statements-절차적-문장"><strong>Procedural Statements (절차적 문장)</strong></h1>
<p>Procedural Statements는 <strong>순차적(Sequential)으로 실행되는 문장</strong>을 의미하며, 주로 <strong>always 블록</strong> 또는 <strong>initial 블록</strong> 내부에서 사용됩니다.  </p>
<h2 id="1-procedural-blocks-절차적-블록"><strong>1. Procedural Blocks (절차적 블록)</strong></h2>
<p>Verilog에서는 <strong>프로시저 블록(Procedural Block)</strong>을 사용하여 논리 동작을 정의합니다. 대표적으로 다음과 같은 두 가지가 있습니다.</p>
<h3 id="1-initial-블록"><strong>(1) <code>initial</code> 블록</strong></h3>
<ul>
<li><strong>시뮬레이션 시작 시 한 번만 실행</strong>되는 블록  </li>
<li><strong>Testbench(테스트벤치)에서 주로 사용됨</strong>  </li>
<li>합성(Synthesis) 불가  </li>
</ul>
<pre><code class="language-verilog">initial begin
    a = 0;
    #10 a = 1;  // 10ns 후 a를 1로 설정
end</code></pre>
<h3 id="2-always-블록"><strong>(2) <code>always</code> 블록</strong></h3>
<ul>
<li><strong>특정 조건(Event)에 따라 반복 실행</strong>됨  </li>
<li>하드웨어 설계에서 <strong>순차 논리(Flip-Flop, Latch 등) 및 조합 논리(Combinational Logic) 생성에 사용</strong>됨  </li>
</ul>
<pre><code class="language-verilog">always @(posedge clk) begin
    q &lt;= d;  // clk의 rising edge마다 q에 d를 저장
end</code></pre>
<hr>
<h2 id="2-procedural-assignments-절차적-할당"><strong>2. Procedural Assignments (절차적 할당)</strong></h2>
<p><strong>Procedural Block</strong> 내부에서 값을 할당하는 문장입니다.</p>
<h3 id="1--blocking-assignment"><strong>(1) <code>= (blocking assignment)</code></strong></h3>
<ul>
<li><strong>순차적으로 실행됨 (Blocking)</strong></li>
<li>앞의 문장이 끝난 후 다음 문장이 실행됨  </li>
</ul>
<pre><code class="language-verilog">always @(posedge clk) begin
    a = b;   // b의 값을 a에 즉시 할당 (blocking)
    c = a;   // 위의 할당이 완료된 후 실행됨
end</code></pre>
<h3 id="2--non-blocking-assignment"><strong>(2) <code>&lt;= (non-blocking assignment)</code></strong></h3>
<ul>
<li><strong>동시에 실행됨 (Non-blocking)</strong></li>
<li>모든 문장이 동시에 실행되므로 <strong>Register(레지스터) 동작을 표현하는 데 적합</strong>  </li>
</ul>
<pre><code class="language-verilog">always @(posedge clk) begin
    a &lt;= b;   // b를 a에 비동기적으로 할당
    c &lt;= a;   // 기존 a 값을 c에 할당 (이전 값이 유지됨)
end</code></pre>
<hr>
<h2 id="3-event-control-이벤트-제어"><strong>3. Event Control (이벤트 제어)</strong></h2>
<p>Verilog에서는 특정 <strong>이벤트(Event)가 발생할 때 블록이 실행</strong>됩니다.  </p>
<h3 id="1-일반적인-이벤트-제어"><strong>(1) 일반적인 이벤트 제어</strong></h3>
<ul>
<li><code>@()</code> 구문을 사용하여 특정 신호 변화 시 블록을 실행  </li>
</ul>
<pre><code class="language-verilog">always @(clk)   // clk이 변할 때마다 실행
    q = d;</code></pre>
<h3 id="2-edge-트리거-이벤트-제어"><strong>(2) Edge 트리거 이벤트 제어</strong></h3>
<ul>
<li><code>posedge</code> : <strong>상승 엣지(positive edge, 0 → 1)에서 실행</strong>  </li>
<li><code>negedge</code> : <strong>하강 엣지(negative edge, 1 → 0)에서 실행</strong>  </li>
</ul>
<pre><code class="language-verilog">always @(posedge clk)  // clk 상승 엣지에서 실행
    q &lt;= d;</code></pre>
<h3 id="3-비동기asynchronous-리셋을-포함한-이벤트-제어"><strong>(3) 비동기(Asynchronous) 리셋을 포함한 이벤트 제어</strong></h3>
<ul>
<li><code>rst</code>가 0이면 <code>q</code>를 0으로 초기화  </li>
<li>그렇지 않으면 <code>clk</code> 상승 엣지에서 <code>q</code>에 <code>d</code>를 저장  </li>
</ul>
<pre><code class="language-verilog">always @(posedge clk or negedge rst) begin
    if (!rst) 
        q &lt;= 0;  // rst가 0이면 q를 초기화
    else 
        q &lt;= d;  // clk 상승 엣지에서 d를 저장
end</code></pre>
<hr>
<h2 id="4-procedural-statements-절차적-문장"><strong>4. Procedural Statements (절차적 문장)</strong></h2>
<p>절차적 문장은 <code>always</code> 또는 <code>initial</code> 블록 내부에서 사용됩니다.  </p>
<h3 id="1-if-else-문"><strong>(1) If-Else 문</strong></h3>
<ul>
<li>조건문을 사용하여 분기 처리  </li>
<li><strong>조건이 중복될 경우, 가장 먼저 참(<code>true</code>)이 되는 조건이 실행됨</strong>  </li>
</ul>
<pre><code class="language-verilog">always @(posedge clk) begin
    if (a &gt; b) 
        result &lt;= 1;
    else if (a == b) 
        result &lt;= 0;
    else 
        result &lt;= -1;
end</code></pre>
<h3 id="2-case-문"><strong>(2) Case 문</strong></h3>
<ul>
<li>여러 개의 조건을 검사하는 경우 <code>case</code> 문 사용  </li>
<li>기본적으로 <code>case</code>는 <strong>완전히 일치하는 경우만 실행됨</strong>  </li>
</ul>
<pre><code class="language-verilog">always @(posedge clk) begin
    case (sel)
        2&#39;b00: out &lt;= in0;
        2&#39;b01: out &lt;= in1;
        2&#39;b10: out &lt;= in2;
        2&#39;b11: out &lt;= in3;
    endcase
end</code></pre>
<h4 id="3-casex-및-casez-문"><strong>(3) <code>casex</code> 및 <code>casez</code> 문</strong></h4>
<ul>
<li><code>casex</code> : <code>x</code>, <code>z</code>, <code>?</code>를 <strong>Don&#39;t Care</strong>로 간주  </li>
<li><code>casez</code> : <code>z</code>, <code>?</code>만 <strong>Don&#39;t Care</strong>로 간주  </li>
</ul>
<pre><code class="language-verilog">casex (opcode)
    4&#39;b1xxx: out = 4&#39;b0001;  // MSB가 1이면 실행
    4&#39;b01xx: out = 4&#39;b0010;  // 상위 2비트가 01이면 실행
endcase</code></pre>
<pre><code class="language-verilog">casez (opcode)
    4&#39;b1zz0: out = 4&#39;b1000;  // z는 무시됨
endcase</code></pre>
<hr>
<h2 id="5-loop-statements-반복문"><strong>5. Loop Statements (반복문)</strong></h2>
<h3 id="1-repeat-문"><strong>(1) <code>repeat</code> 문</strong></h3>
<ul>
<li>지정한 횟수만큼 루프 실행  </li>
</ul>
<pre><code class="language-verilog">repeat (5) begin
    a = a + 1;  // a를 5번 증가
end</code></pre>
<h3 id="2-while-문"><strong>(2) <code>while</code> 문</strong></h3>
<ul>
<li>조건이 참일 동안 루프 실행  </li>
<li><strong>합성(Synthesis) 불가능 → 시뮬레이션에서만 사용</strong>  </li>
</ul>
<pre><code class="language-verilog">while (a &lt; 10) begin
    a = a + 1;
end</code></pre>
<h3 id="3-forever-문"><strong>(3) <code>forever</code> 문</strong></h3>
<ul>
<li>무한 반복 (종료 조건 없음)  </li>
<li><strong>하드웨어 합성 불가능 → 시뮬레이션에서만 사용</strong>  </li>
</ul>
<pre><code class="language-verilog">forever begin
    #10 clk = ~clk;  // 10ns마다 clk 반전
end</code></pre>
<hr>
<h2 id="6-fork-join-병렬-실행"><strong>6. Fork-Join (병렬 실행)</strong></h2>
<p>Verilog는 기본적으로 <code>begin...end</code>를 사용하면 <strong>순차 실행</strong>하지만,<br><code>fork...join</code>을 사용하면 <strong>동시에 실행(병렬 실행)</strong>됩니다.</p>
<pre><code class="language-verilog">fork
    #10 a = 1;
    #20 b = 2;
    #30 c = 3;
join</code></pre>
<p>위 코드는 <code>a</code>, <code>b</code>, <code>c</code>가 <strong>동시에 변경됨</strong> (비동기 실행).<br>만약 <code>begin...end</code>를 사용했다면 <strong>순차적으로 실행</strong>됩니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Verilog: value, operators]]></title>
            <link>https://velog.io/@na_itsso/Verilog-value-operators</link>
            <guid>https://velog.io/@na_itsso/Verilog-value-operators</guid>
            <pubDate>Tue, 25 Feb 2025 07:34:57 GMT</pubDate>
            <description><![CDATA[<h2 id="verilog-vs-vhdl"><strong>Verilog vs VHDL</strong></h2>
<h3 id="letch-edge-triggered"><strong>Letch</strong> (Edge Triggered):</h3>
<ul>
<li><strong>Letch</strong>는 <strong>엣지 트리거</strong> 방식을 사용합니다. 즉, <strong>신호가 변화하는 순간</strong>에 동작합니다.</li>
<li><strong>입력 신호의 변화(엣지)</strong>에 의해 동작을 시작하는 메모리 요소를 나타냅니다.</li>
<li>일반적으로 <strong>순차 회로</strong>에서 사용됩니다.</li>
</ul>
<h3 id="ff-flip-flop-level-triggered"><strong>FF (Flip-Flop)</strong> (Level Triggered):</h3>
<ul>
<li><strong>FF</strong>는 <strong>레벨 트리거</strong> 방식을 사용합니다. 즉, <strong>특정 레벨</strong>이 유지되는 동안 동작합니다.</li>
<li>일반적으로 <strong>레벨 감지</strong> 방식으로, <strong>지속적인 신호</strong> 상태에 따라 동작합니다.</li>
</ul>
<hr>
<h2 id="logic-value-4-value-logic-system"><strong>Logic Value (4-Value Logic System)</strong></h2>
<p>Verilog는 <strong>4-Value Logic System</strong>을 지원하며, 이는 <strong>디지털 회로의 신호 값을 표현하는 다양한 상태</strong>를 포함합니다.</p>
<h3 id="각-logic-값의-의미"><strong>각 Logic 값의 의미</strong></h3>
<ul>
<li><strong><code>0</code></strong>: <code>false</code>, <code>ground</code>, <code>low</code>, <code>VSS</code>, <code>negative assertion</code> (부정적인 신호 또는 낮은 전압)</li>
<li><strong><code>1</code></strong>: <code>true</code>, <code>high</code>, <code>Power</code>, <code>VDD</code>, <code>VCC</code>, <code>positive assertion</code> (긍정적인 신호 또는 높은 전압)</li>
<li><strong><code>x</code></strong>: <strong>bus 충돌</strong>(unknown state) 또는 <strong>미초기화된 상태</strong>. 이 값은 여러 신호가 동시에 충돌할 때 나타날 수 있습니다.</li>
<li><strong><code>z</code></strong>: <strong>High Impedance (Hi-Z)</strong> 상태를 나타냅니다. 이는 <strong>세트되지 않거나 연결되지 않은 상태</strong>로, 일반적으로 <strong>Tri-state 버퍼</strong>에서 사용됩니다.</li>
</ul>
<hr>
<h2 id="1-data-types"><strong>1. Data Types</strong></h2>
<h3 id="nets"><strong>Nets</strong></h3>
<ul>
<li><strong>Nets</strong>는 회로의 <strong>물리적 연결</strong>을 나타냅니다. 예를 들어, <strong>wire</strong>는 물리적인 연결을 의미하며, 신호가 흐를 수 있는 경로를 정의합니다.</li>
<li><code>wire</code>, <code>tri</code>, <code>supply1</code>, <code>supply0</code>, <code>wand</code>, <code>wor</code>, <code>triand</code> 등 여러 가지 타입이 있으며, 주로 <strong>연결된 신호</strong>를 표현할 때 사용됩니다.</li>
</ul>
<h3 id="register"><strong>Register</strong></h3>
<ul>
<li><p><strong>Register</strong>는 <strong>추상적인 저장 요소</strong>입니다. <code>reg</code>, <code>integer</code>, <code>real</code>, <code>time</code> 등 다양한 <strong>데이터 타입</strong>이 포함될 수 있습니다.</p>
</li>
<li><p>순차 회로에서 <strong>값을 저장</strong>하는 데 사용됩니다. 예를 들어 <strong>플립플롭(FF)</strong>나 <strong>레지스터</strong>는 상태를 유지해야 할 때 사용됩니다.</p>
<p><strong>중요</strong>: FF나 letch는 단순히 하드웨어에서 <strong>상태를 저장</strong>하는 요소에 해당합니다. 이를 구체적으로 표현하는 것이 <code>reg</code>, <code>integer</code>, <code>real</code> 등이죠.</p>
</li>
</ul>
<h3 id="parameter"><strong>Parameter</strong></h3>
<ul>
<li><strong>Parameters</strong>는 <strong>런타임 상수</strong>로, <strong>하드웨어 설계에서 유동적인 상수값</strong>을 정의하는 데 사용됩니다. 예를 들어, <code>parameter WIDTH = 8;</code>와 같이 상수 값을 정의할 수 있습니다.</li>
<li><strong>module parameter</strong>는 각 인스턴스별로 <code>#()</code> 또는 <code>defparam</code>으로 <strong>오버라이드(값을 변경)</strong>할 수 있습니다.</li>
</ul>
<hr>
<h2 id="concept-of-type"><strong>Concept of Type</strong></h2>
<h3 id="타입-개념"><strong>타입 개념</strong></h3>
<ul>
<li>Verilog에서는 각 변수의 타입을 <strong>명시적으로 지정</strong>할 수 있습니다. 예를 들어 <code>wire</code>나 <code>reg</code>와 같은 <strong>기본 타입</strong>이 있습니다.<ul>
<li><strong>Procedural assignment</strong>는 <code>reg</code> 타입에만 가능합니다. 이는 <strong>프로시저적 할당</strong> 방식으로 값이 변경되는 경우에 사용됩니다.</li>
<li><strong>Default</strong>는 보통 <code>wire</code> 타입입니다. 이는 기본적으로 물리적인 신호를 나타내는 데 사용됩니다.</li>
</ul>
</li>
</ul>
<hr>
<h2 id="vectors"><strong>Vectors</strong></h2>
<h3 id="vectors-1"><strong>Vectors</strong></h3>
<ul>
<li><p><strong>Vectors</strong>는 여러 비트로 구성된 신호를 나타냅니다. 예를 들어, <code>reg [7:0] data;</code>는 <strong>8비트 레지스터</strong>를 의미합니다.</p>
</li>
<li><p>비트 벡터는 <strong><code>[msb:lsb]</code></strong>로 표현되며, <strong>크기 조정</strong>을 할 때 주의해야 합니다.</p>
<p><strong>크기 조정(Truncation &amp; Padding)</strong></p>
<ul>
<li><strong>Source가 더 크면</strong>: 더 작은 신호가 오른쪽에서 잘라지며(트렁케이션) 전달됩니다.</li>
<li><strong>Source가 더 작으면</strong>: <strong>패딩</strong>을 통해 왼쪽에서 <code>0</code>으로 채워집니다.</li>
</ul>
</li>
</ul>
<h3 id="literal-values"><strong>Literal Values</strong></h3>
<ul>
<li>Verilog에서 <strong>상수값을 표현할 때</strong> <code>4&#39;b1001</code>, <code>8&#39;d255</code>와 같은 <strong>literal 값을 사용</strong>합니다. </li>
<li>형식: <code>[size]&#39;[base][value]</code><ul>
<li>예: <code>4&#39;b1001</code> = 4비트 바이너리 <code>1001</code></li>
<li><code>4&#39;d9</code> = 10진수 <code>9</code></li>
<li><code>5&#39;o11</code> = 8진수 <code>11</code></li>
</ul>
</li>
</ul>
<h3 id="automatic-extension-of-literals"><strong>Automatic Extension of Literals</strong></h3>
<ul>
<li>Verilog에서는 <strong>상수값을 확장</strong>할 때 <code>MSB</code>(최상위 비트)가 <code>x</code>나 <code>z</code>일 경우, <strong>자동으로 확장</strong>이 될 수 있습니다.</li>
</ul>
<hr>
<h2 id="net-types"><strong>Net Types</strong></h2>
<h3 id="nets-1"><strong>Nets</strong></h3>
<ul>
<li><strong>Nets</strong>는 회로의 물리적 연결을 정의하며, <strong>기본적으로 <code>wire</code> 타입</strong>으로 설정됩니다.</li>
<li><strong>wire</strong> 외에도 다양한 <strong>전달 타입</strong>이 존재합니다:<ul>
<li><strong><code>supply1</code>, <code>supply0</code></strong>: 전원 공급용 신호</li>
<li><strong><code>tri</code></strong>: 트라이 상태 (Hi-Z 상태) 신호</li>
<li><strong><code>wand</code>, <code>wor</code></strong>: AND/OR 결과로서의 연산 신호</li>
</ul>
</li>
</ul>
<h3 id="logic-conflict"><strong>Logic Conflict</strong></h3>
<ul>
<li><strong>Continuous assignment</strong>에서 충돌이 발생할 수 있습니다. 예를 들어 <code>wire</code>로 선언된 신호는 여러 드라이버가 있을 경우 <code>x</code> 값이 될 수 있습니다.</li>
</ul>
<hr>
<h2 id="register-types"><strong>Register Types</strong></h2>
<h3 id="register-types-1"><strong>Register Types</strong></h3>
<ul>
<li><strong>reg</strong>: <strong>unsigned</strong>, 사용자가 정의한 폭을 가진 4-상태 (0, 1, x, z) 값을 가질 수 있습니다.</li>
<li><strong>integer</strong>: <strong>signed</strong>, 32비트 크기의 4-상태 값을 가질 수 있습니다.</li>
<li><strong>실수 타입</strong>: <code>real</code>, <code>time</code>, <code>realtime</code> 등 다양한 데이터 타입을 사용할 수 있습니다.</li>
</ul>
<hr>
<h2 id="choosing-the-correct-data-type"><strong>Choosing the Correct Data Type</strong></h2>
<ul>
<li><strong>input port</strong>: <strong>무조건 net type</strong>으로 선언해야 합니다. (데이터가 외부에서 들어오기 때문)</li>
<li><strong>output port</strong>: <strong><code>reg</code></strong> 또는 <strong><code>net type</code></strong>으로 선언할 수 있습니다. (값을 외부로 내보내는 신호)</li>
<li><strong>inout port</strong>: <strong>무조건 net type</strong>으로 선언합니다. (입출력 모두 가능한 포트)</li>
</ul>
<hr>
<h2 id="parameter-1"><strong>Parameter</strong></h2>
<h3 id="module-parameters"><strong>Module Parameters</strong></h3>
<ul>
<li><strong>Module parameters</strong>는 <strong>각 인스턴스에 대한 상수</strong>를 정의합니다. </li>
<li>예를 들어, 인스턴스를 만들 때 <strong><code>parameter WIDTH=8;</code></strong>과 같이 특정 값들을 설정하고, 이를 <code>#()</code>를 통해 오버라이드할 수 있습니다.</li>
</ul>
<h3 id="local-parameters"><strong>Local Parameters</strong></h3>
<ul>
<li><strong>Local parameters</strong>는 <strong>모듈 내에서만 사용되는 상수</strong>입니다.</li>
<li><strong>Override할 수 없으며</strong> 상수 값으로 고정되어 있습니다.</li>
</ul>
<hr>
<h2 id="arrays"><strong>Arrays</strong></h2>
<ul>
<li>Verilog에서는 <strong>다차원 배열</strong>을 설정할 수 있습니다. 예를 들어 <code>reg [7:0] data[0:99];</code>는 <strong>100개의 8비트 배열</strong>을 정의하는 방식입니다.</li>
</ul>
<hr>
<h2 id="2-operators"><strong>2. Operators</strong></h2>
<p>arithmetic
bitwise
logical: operand reduction by a single bit operation
*reduction
unary reduction operators : 결과 1, 0, x
shift
relational
== : logical equality operator 
===: case equality operator
conditional
triset, mux 구현할 때 사용
?:
concatenation
replication</p>
<p>알겠습니다! 이번에는 <strong>Verilog에서 사용되는 다양한 연산자(Operators)</strong>에 대해 자세히 설명하겠습니다. 각 연산자의 종류와 특징을 설명하고, 어떻게 사용되는지 구체적인 예시를 추가하여 정리해 드리겠습니다.</p>
<hr>
<h2 id="2-operators-1"><strong>2. Operators</strong></h2>
<h3 id="1-arithmetic-operators-산술-연산자"><strong>1. Arithmetic Operators (산술 연산자)</strong></h3>
<p>산술 연산자는 수학적 계산을 수행하는 데 사용됩니다.</p>
<table>
<thead>
<tr>
<th>연산자</th>
<th>설명</th>
<th>예시</th>
</tr>
</thead>
<tbody><tr>
<td><code>+</code></td>
<td>덧셈</td>
<td><code>a + b</code></td>
</tr>
<tr>
<td><code>-</code></td>
<td>뺄셈</td>
<td><code>a - b</code></td>
</tr>
<tr>
<td><code>*</code></td>
<td>곱셈</td>
<td><code>a * b</code></td>
</tr>
<tr>
<td><code>/</code></td>
<td>나눗셈</td>
<td><code>a / b</code></td>
</tr>
<tr>
<td><code>%</code></td>
<td>나머지</td>
<td><code>a % b</code></td>
</tr>
<tr>
<td><code>**</code></td>
<td>거듭제곱</td>
<td><code>a ** b</code></td>
</tr>
</tbody></table>
<h4 id="예시">예시:</h4>
<pre><code class="language-verilog">reg [3:0] a, b, sum;
a = 4&#39;b0011;  // 3
b = 4&#39;b0101;  // 5
sum = a + b;  // 8 (4&#39;b1000)</code></pre>
<h3 id="2-bitwise-operators-비트-단위-연산자"><strong>2. Bitwise Operators (비트 단위 연산자)</strong></h3>
<p>비트 단위 연산자는 각 비트에 대해 연산을 수행합니다. 이러한 연산자는 <code>wire</code> 타입과 같이 <strong>net type</strong>에 사용됩니다.</p>
<table>
<thead>
<tr>
<th>연산자</th>
<th>설명</th>
<th>예시</th>
</tr>
</thead>
<tbody><tr>
<td><code>&amp;</code></td>
<td>비트 AND</td>
<td><code>a &amp; b</code></td>
</tr>
<tr>
<td>`</td>
<td>`</td>
<td>비트 OR</td>
</tr>
<tr>
<td><code>^</code></td>
<td>비트 XOR</td>
<td><code>a ^ b</code></td>
</tr>
<tr>
<td><code>~</code></td>
<td>비트 NOT (단일 피연산자)</td>
<td><code>~a</code></td>
</tr>
<tr>
<td><code>~&amp;</code></td>
<td>NOR (비트 AND 후 부정)</td>
<td><code>~(a &amp; b)</code></td>
</tr>
<tr>
<td>`~</td>
<td>`</td>
<td>NAND (비트 OR 후 부정)</td>
</tr>
<tr>
<td><code>^~</code></td>
<td>XNOR (비트 XOR 후 부정)</td>
<td><code>~(a ^ b)</code></td>
</tr>
</tbody></table>
<h4 id="예시-1">예시:</h4>
<pre><code class="language-verilog">reg [3:0] a, b, result;
a = 4&#39;b1101;  // 13
b = 4&#39;b1011;  // 11
result = a &amp; b;  // 4&#39;b1001 (AND 연산)
result = a | b;  // 4&#39;b1111 (OR 연산)
result = a ^ b;  // 4&#39;b0110 (XOR 연산)</code></pre>
<h3 id="3-logical-operators-논리-연산자"><strong>3. Logical Operators (논리 연산자)</strong></h3>
<p>논리 연산자는 <strong>boolean 값</strong>을 처리하는 데 사용됩니다.</p>
<table>
<thead>
<tr>
<th>연산자</th>
<th>설명</th>
<th>예시</th>
</tr>
</thead>
<tbody><tr>
<td><code>&amp;&amp;</code></td>
<td>논리 AND (단락 평가)</td>
<td><code>a &amp;&amp; b</code></td>
</tr>
<tr>
<td>`</td>
<td></td>
<td>`</td>
</tr>
<tr>
<td><code>!</code></td>
<td>논리 NOT</td>
<td><code>!a</code></td>
</tr>
</tbody></table>
<h4 id="예시-2">예시:</h4>
<pre><code class="language-verilog">reg a, b, result;
a = 1&#39;b1;  // true
b = 1&#39;b0;  // false
result = a &amp;&amp; b;  // 1&#39;b0 (AND 연산)
result = a || b;  // 1&#39;b1 (OR 연산)</code></pre>
<h3 id="4-reduction-operators-축소-연산자"><strong>4. Reduction Operators (축소 연산자)</strong></h3>
<p>축소 연산자는 <strong>벡터의 모든 비트를 하나의 값으로 축소</strong>하는 데 사용됩니다. 주로 <strong><code>wire</code> 타입</strong>에 사용됩니다.</p>
<table>
<thead>
<tr>
<th>연산자</th>
<th>설명</th>
<th>예시</th>
</tr>
</thead>
<tbody><tr>
<td><code>&amp;</code></td>
<td>AND 축소</td>
<td><code>&amp;a</code> (모든 비트가 AND 연산됨)</td>
</tr>
<tr>
<td>`</td>
<td>`</td>
<td>OR 축소</td>
</tr>
<tr>
<td><code>^</code></td>
<td>XOR 축소</td>
<td><code>^a</code> (모든 비트가 XOR 연산됨)</td>
</tr>
<tr>
<td><code>~&amp;</code></td>
<td>NOR 축소</td>
<td><code>~&amp;a</code> (모든 비트가 NOR 연산됨)</td>
</tr>
<tr>
<td>`~</td>
<td>`</td>
<td>NAND 축소</td>
</tr>
</tbody></table>
<h4 id="예시-3">예시:</h4>
<pre><code class="language-verilog">reg [3:0] a;
a = 4&#39;b1011;  // 4비트 벡터
wire and_result;
assign and_result = &amp;a;  // AND 축소 -&gt; 1&#39;b0</code></pre>
<h3 id="5-conditional-삼항-operator"><strong>5. Conditional (삼항) Operator</strong></h3>
<p>조건부 연산자는 <strong>if-else</strong> 구문처럼 작동하지만, <strong>한 줄로 간단하게 표현</strong>할 수 있습니다.
if else 문 대신에 사용도 가능하다.</p>
<table>
<thead>
<tr>
<th>연산자</th>
<th>설명</th>
<th>예시</th>
</tr>
</thead>
<tbody><tr>
<td><code>? :</code></td>
<td>조건부 연산자 (if-else)</td>
<td><code>a ? b : c</code> (a가 참이면 b, 아니면 c)</td>
</tr>
</tbody></table>
<h4 id="예시-4">예시:</h4>
<pre><code class="language-verilog">reg [3:0] a, b, c, result;
a = 4&#39;b1100;
b = 4&#39;b1010;
c = 4&#39;b0110;
result = (a == 4&#39;b1100) ? b : c;  // 4&#39;b1010 (a가 참이면 b)</code></pre>
<h3 id="6-concatenation-operator-연결-연산자"><strong>6. Concatenation Operator (연결 연산자)</strong></h3>
<p>연결 연산자는 여러 비트나 <strong>벡터를 합치는</strong> 데 사용됩니다.</p>
<table>
<thead>
<tr>
<th>연산자</th>
<th>설명</th>
<th>예시</th>
</tr>
</thead>
<tbody><tr>
<td><code>{}</code></td>
<td>벡터 연결</td>
<td><code>{a, b}</code> (a와 b를 연결)</td>
</tr>
</tbody></table>
<h4 id="예시-5">예시:</h4>
<pre><code class="language-verilog">reg [3:0] a, b, result;
a = 4&#39;b1100;
b = 4&#39;b1010;
result = {a, b};  // 8비트 벡터: 4&#39;b11001010</code></pre>
<h3 id="7-replication-operator-복제-연산자"><strong>7. Replication Operator (복제 연산자)</strong></h3>
<p>복제 연산자는 <strong>하나의 값을 여러 번 반복하여</strong> 벡터로 만드는 데 사용됩니다.</p>
<table>
<thead>
<tr>
<th>연산자</th>
<th>설명</th>
<th>예시</th>
</tr>
</thead>
<tbody><tr>
<td><code>{}</code></td>
<td>값 복제</td>
<td><code>{n{a}}</code> (a를 n번 반복)</td>
</tr>
</tbody></table>
<h4 id="예시-6">예시:</h4>
<pre><code class="language-verilog">reg [3:0] a, result;
a = 4&#39;b1010;
result = {3{a}};  // 12비트 벡터: 4&#39;b101010101010</code></pre>
<p>좋아요! 추가적으로 <strong>Shift 연산자, 관계 연산자, 논리/케이스 동등 연산자</strong>에 대해 설명하겠습니다.  </p>
<h3 id="8-shift-operators-시프트-연산자"><strong>8. Shift Operators (시프트 연산자)</strong></h3>
<p>Shift 연산자는 비트를 <strong>왼쪽 또는 오른쪽으로 이동</strong>하는 데 사용됩니다.  </p>
<table>
<thead>
<tr>
<th>연산자</th>
<th>설명</th>
<th>예시</th>
</tr>
</thead>
<tbody><tr>
<td><code>&lt;&lt;</code></td>
<td>논리 왼쪽 시프트 (Logical Left Shift)</td>
<td><code>a &lt;&lt; b</code></td>
</tr>
<tr>
<td><code>&gt;&gt;</code></td>
<td>논리 오른쪽 시프트 (Logical Right Shift)</td>
<td><code>a &gt;&gt; b</code></td>
</tr>
<tr>
<td><code>&lt;&lt;&lt;</code></td>
<td>산술 왼쪽 시프트 (Arithmetic Left Shift)</td>
<td><code>a &lt;&lt;&lt; b</code></td>
</tr>
<tr>
<td><code>&gt;&gt;&gt;</code></td>
<td>산술 오른쪽 시프트 (Arithmetic Right Shift)</td>
<td><code>a &gt;&gt;&gt; b</code></td>
</tr>
</tbody></table>
<h4 id="논리-시프트-vs-산술-시프트-차이점"><strong>논리 시프트 vs. 산술 시프트 차이점</strong></h4>
<ul>
<li><strong>논리 시프트(<code>&lt;&lt;</code>, <code>&gt;&gt;</code>)</strong>: 비어 있는 자리를 <code>0</code>으로 채운다.</li>
<li><strong>산술 시프트(<code>&lt;&lt;&lt;</code>, <code>&gt;&gt;&gt;</code>)</strong>: 오른쪽 시프트 시 <strong>부호 비트를 유지</strong>한다.</li>
</ul>
<h4 id="예제"><strong>예제</strong></h4>
<pre><code class="language-verilog">reg [7:0] a, b;
a = 8&#39;b00001111;  // 15
b = a &lt;&lt; 2;       // 8&#39;b00111100 (왼쪽으로 2비트 이동, 60)
b = a &gt;&gt; 2;       // 8&#39;b00000011 (오른쪽으로 2비트 이동, 3)</code></pre>
<h4 id="산술-시프트-예제"><strong>산술 시프트 예제</strong></h4>
<pre><code class="language-verilog">reg signed [7:0] c;
c = -8&#39;sd4;        // 8&#39;b11111100 (-4)
c = c &gt;&gt;&gt; 1;       // 8&#39;b11111110 (-2) (MSB 유지)</code></pre>
<h3 id="9-relational-operators-관계-연산자"><strong>9. Relational Operators (관계 연산자)</strong></h3>
<p>관계 연산자는 <strong>두 값 간의 크기 비교</strong>를 수행합니다. 결과는 <strong>1(<code>true</code>) 또는 0(<code>false</code>)</strong>이 됩니다.</p>
<table>
<thead>
<tr>
<th>연산자</th>
<th>설명</th>
<th>예시</th>
</tr>
</thead>
<tbody><tr>
<td><code>&gt;</code></td>
<td>크다 (greater than)</td>
<td><code>a &gt; b</code></td>
</tr>
<tr>
<td><code>&lt;</code></td>
<td>작다 (less than)</td>
<td><code>a &lt; b</code></td>
</tr>
<tr>
<td><code>&gt;=</code></td>
<td>크거나 같다 (greater than or equal to)</td>
<td><code>a &gt;= b</code></td>
</tr>
<tr>
<td><code>&lt;=</code></td>
<td>작거나 같다 (less than or equal to)</td>
<td><code>a &lt;= b</code></td>
</tr>
</tbody></table>
<h4 id="예제-1"><strong>예제</strong></h4>
<pre><code class="language-verilog">reg [3:0] a, b;
a = 4&#39;b1010;  // 10
b = 4&#39;b0101;  // 5
if (a &gt; b)    // 10 &gt; 5 → 참 (1)
    $display(&quot;a가 b보다 크다&quot;);</code></pre>
<h3 id="10-equality-operators-동등-연산자"><strong>10. Equality Operators (동등 연산자)</strong></h3>
<h4 id="논리-동등-연산--"><strong>논리 동등 연산 (<code>==</code>, <code>!=</code>)</strong></h4>
<ul>
<li><code>==</code> : 두 값이 <strong>같으면</strong> <code>1</code>을 반환 (논리적 동등)</li>
<li><code>!=</code> : 두 값이 <strong>다르면</strong> <code>1</code>을 반환 (논리적 비동등)  </li>
</ul>
<h4 id="예제-2"><strong>예제</strong></h4>
<pre><code class="language-verilog">reg [3:0] a, b;
a = 4&#39;b1010;  // 10
b = 4&#39;b1010;  // 10
if (a == b)   // 참 (1)
    $display(&quot;a와 b는 같다&quot;);</code></pre>
<p><strong>⚠ 주의</strong>: <code>x</code> 또는 <code>z</code>가 포함된 값을 비교하면 결과가 <code>X</code>가 될 수도 있음.</p>
<h4 id="case-equality-operators--"><strong>Case Equality Operators (<code>===</code>, <code>!==</code>)</strong></h4>
<ul>
<li><code>===</code> : 두 값이 <strong>모든 비트가 완전히 같아야</strong> <code>1</code>을 반환 (비교할 때 <code>x</code>와 <code>z</code>도 고려)</li>
<li><code>!==</code> : 두 값이 <strong>하나라도 다르면</strong> <code>1</code>을 반환 (비교할 때 <code>x</code>와 <code>z</code>도 고려)</li>
</ul>
<h4 id="논리-동등-vs-케이스-동등-비교"><strong>논리 동등(<code>==</code>) vs. 케이스 동등(<code>===</code>) 비교</strong></h4>
<table>
<thead>
<tr>
<th>비교 연산자</th>
<th>비교 결과</th>
</tr>
</thead>
<tbody><tr>
<td><code>4&#39;b10xx == 4&#39;b1010</code></td>
<td><code>X</code> (논리 비교는 <code>x</code> 고려 안함)</td>
</tr>
<tr>
<td><code>4&#39;b10xx === 4&#39;b1010</code></td>
<td><code>0</code> (<code>x</code>도 엄격하게 비교)</td>
</tr>
<tr>
<td><code>4&#39;b1010 !== 4&#39;b1010</code></td>
<td><code>0</code> (완전히 같음)</td>
</tr>
<tr>
<td><code>4&#39;b10xx !== 4&#39;b1010</code></td>
<td><code>1</code> (<code>x</code> 때문에 다름)</td>
</tr>
</tbody></table>
<h4 id="예제-3"><strong>예제</strong></h4>
<pre><code class="language-verilog">reg [3:0] a, b;
a = 4&#39;b10xx;
b = 4&#39;b1010;

if (a == b)   // 결과: X (논리 비교)
    $display(&quot;a와 b는 같다&quot;);

if (a === b)  // 결과: 0 (모든 비트 다 비교)
    $display(&quot;a와 b는 완전히 같다&quot;);
else
    $display(&quot;a와 b는 다르다&quot;);</code></pre>
<h3 id="operator-precedence">Operator Precedence</h3>
<p>외우기 힘드니 괄호를 사용하자</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Lab 1 Compile, Elaborate, and Simulate a 2-to-1 mux Design]]></title>
            <link>https://velog.io/@na_itsso/Lab-1-Compile-Elaborate-and-Simulate-a-2-to-1-mux-Design</link>
            <guid>https://velog.io/@na_itsso/Lab-1-Compile-Elaborate-and-Simulate-a-2-to-1-mux-Design</guid>
            <pubDate>Mon, 24 Feb 2025 08:13:53 GMT</pubDate>
            <description><![CDATA[<h2 id="source">source</h2>
<h3 id="muxv">mux.v</h3>
<pre><code>
`timescale 1 ns / 1 ns
//port 
module mux
(
 output reg y ,
 input wire s ,
 input wire i1 ,
 input wire i0
);

 always @ (s or i1 or i0)
  if (s == 1)
   y = i1 ;
  else
   y = i0 ;

endmodule
~
</code></pre><h3 id="mux_testv">mux_test.v</h3>
<pre><code>`resetall
//`include &quot;defines.inc&quot;
`timescale 1 ns / 1 ns

module mux_test;

  wire  y ;
  reg   i0 ;
  reg   i1 ;
  reg   s ;

//MUX instance([module name] [instance name]
 mux  mux1(
        y,
        s,
        i1,
        i0
        );
 task display ;
  begin
   $display
   (
    &quot;time=%0d&quot; , $time, &quot; ns&quot;
  , &quot; s=&quot;, s
  , &quot; i1=&quot;, i1
  , &quot; i0=&quot;, i0
  , &quot; y=&quot;, y
  );
  end
 endtask

 initial
  begin
  s = 0 ; i1 = 0; i0 = 1 ; #10 ; display;
  s = 0 ; i1 = 1; i0 = 0 ; #10 ; display;
  s = 1 ; i1 = 0; i0 = 1 ; #10 ; display;
  s = 1 ; i1 = 1; i0 = 0 ; #10 ; display;
 end

endmodule
</code></pre><h2 id="xmvlog">xmvlog</h2>
<p><img src="https://velog.velcdn.com/images/na_itsso/post/9e39160b-6ebd-4e36-88b9-611093dadfe6/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/na_itsso/post/6072caf1-5298-4484-a812-1182ebdd2646/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/na_itsso/post/6d6700ce-6c9c-4d0c-a154-b5236c230ac7/image.png" alt=""></p>
<h2 id="xmelab">xmelab</h2>
<p><img src="https://velog.velcdn.com/images/na_itsso/post/aea48cd3-1e6b-4d0c-baa1-6dbc7a30fb54/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/na_itsso/post/d19fb362-b28b-4a20-a993-f9ac490538cd/image.png" alt=""></p>
<h4 id="xmelab--access-rwc-top-gui-접근-설정">xmelab -access RWC top (gui 접근 설정)</h4>
<h2 id="xmsim">xmsim</h2>
<p><img src="https://velog.velcdn.com/images/na_itsso/post/4ac58343-59aa-4fe4-ad68-05951649dea3/image.png" alt=""></p>
<h4 id="xmsim--gui--run-mux_test">xmsim -gui -run mux_test</h4>
<p><img src="https://velog.velcdn.com/images/na_itsso/post/8f126889-45c4-483c-92e8-55a609179b98/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[10. Multiprocessor Scheduling]]></title>
            <link>https://velog.io/@na_itsso/10.-Multiprocessor-Scheduling</link>
            <guid>https://velog.io/@na_itsso/10.-Multiprocessor-Scheduling</guid>
            <pubDate>Sat, 19 Oct 2024 07:18:14 GMT</pubDate>
            <description><![CDATA[<h1 id="10-multiprocessor-scheduling">10. Multiprocessor Scheduling</h1>
<p>Multicore: Multiple CPU cores are packed onto a single chip.
-&gt; using <strong>threads</strong> (to run in parallel)
-&gt; How to schedule jobs on multiple CPUS(or cores)?</p>
<h2 id="single-cpu-with-cache">Single CPU with Cache</h2>
<ul>
<li>Cache: <ul>
<li>small, fast, popular data의 copy들을 가진다.</li>
<li>temporal &amp; spatial 지역성 활용</li>
</ul>
</li>
<li>Main memory: 모든 데이터를 저장, slower than cache</li>
</ul>
<h2 id="cache-coherence캐시일관성">Cache Coherence(캐시일관성)</h2>
<p>:여러 캐시들이 동일한 메모리 위치에 대한 데이터를 보유할 때, 각 캐시가 최신의 일관된 데이터를 유지하도록 보장하는 메커니즘</p>
<ul>
<li>how?: 여러개 프로세스들이 메모래에 갱신할 때 항상 공유되도록 한다.(<strong>bus snooping</strong>)</li>
<li>캐시는 자신과 메모리르 ㄹ연결하는 버스의 통신상황 계속 모니터링, 캐시 변경 발생시<ul>
<li>invalidate protocol: 해당 데이터의 복사본을 무효화 시킨다.</li>
<li>update protocol : 해당 데이터의 모든 복사본도 업데이트 한다. <h2 id="synchronization">Synchronization</h2>
</li>
</ul>
</li>
<li>lock(&amp;m), unlock(&amp;m) 필요</li>
<li>ex) list에서 원소 제거하는 과정:  critical section 임.</li>
<li>fine grained 하게 최대한 작게 임계구간 잡아야함.</li>
<li>locking 많이 -&gt; concurrency 감소 = 성능 감소<h2 id="cache-affinity-processor-affinity">Cache Affinity (Processor Affinity)</h2>
: 프로세스가 다음에 실행될 때 동일한 CPU에서 실행되는 것이 유리하다.<ul>
<li>왜냐하면, 해당 CPU 캐시에 일부 정보(state)가 이미 존재하고 있기 때무에 더 빨리 실행될 것이기 때문이다. <h2 id="single-queue-multiprocessor-schedulingsqms">Single Queue Multiprocessor Scheduling(SQMS)<img src="https://velog.velcdn.com/images/na_itsso/post/a1e2a7fe-c0d3-4c95-a157-7ec6d2e03196/image.png" alt=""></h2>
</li>
</ul>
</li>
<li>모든 job들이  single queue에 scheduled.</li>
<li>각 CPU는 <strong><em>global shared queue</em></strong>를 보고 다음 job을 고른다.</li>
<li>문제:<ul>
<li>작업이 너무 자주 서로 다른 큐로 이동한다.(스케쥴링 효율저하)(<strong>cache affinity저하</strong>)</li>
<li>공유되는 큐를 사용하므로 locking 형식 필요 -&gt; <strong>확장성(scalability)이 떨어진다.</strong><h3 id="scheduling-example-with-cache-affinity">Scheduling Example with Cache affinity<img src="https://velog.velcdn.com/images/na_itsso/post/0db025d4-c556-4a36-b966-964d39b747ea/image.png" alt=""></h3>
</li>
</ul>
</li>
<li>Preserving affinity: E 제외 다른 process들은 움직이지 않음.</li>
<li>구현 복잡<h2 id="multi-queque-multiprocessor-schedulingmqms">Multi-Queque Multiprocessor Scheduling(MQMS)</h2>
</li>
<li>단일 queue 문제로 인해, MQMS는 큐도 여러개이다!(CPU 마다 각자 큐 가짐)<ul>
<li>각 큐는 RR 혹은 다른 스케쥴링 알아서...</li>
</ul>
</li>
<li>job은 하나의 scheduling queue에 고정.<ul>
<li><strong>data sharing과 동기화 문제 방지</strong>한다.</li>
<li>CPU 개수가 증가할수록, 큐도 증가하기 때문이다.</li>
</ul>
</li>
<li>장점: 나은 scability, cache affinity<img src="https://velog.velcdn.com/images/na_itsso/post/94580f19-8cc8-45c2-b4d3-3fe31affe169/image.png" alt=""><h3 id="문제-load-imbalance-issue">문제: Load Imbalance issue <img src="https://velog.velcdn.com/images/na_itsso/post/9c59239a-8eef-4572-b466-bafd1da1e881/image.png" alt=""></h3>
</li>
<li>여러개 큐를 사용하므로 load imbalance issue 발생...</li>
<li>그런데 만약 C가 끝나면 , A가 B,D보다 2배의 CPU 차지</li>
<li>심지어 만야 A가 끝나면, CPU0은 놀게 된다.<h3 id="해결-migrationjob-옮기기">해결: Migration(job 옮기기)</h3>
: 작업을 한 CPU에서 다른 CPU로 이주시키기<img src="https://velog.velcdn.com/images/na_itsso/post/65b4dcbc-7779-4a67-b8e2-99ecf36d8eb7/image.png" alt=""></li>
<li>그러나 한번의 이주만으로는 문제 해결 안됨. 지속적 이주가 필요하다<img src="https://velog.velcdn.com/images/na_itsso/post/ddf68684-b5b5-46a2-bf9b-dacb9fcf19d6/image.png" alt=""></li>
</ul>
<h3 id="migration-필요-여부-결정-how-work-stealing">Migration 필요 여부 결정 how? Work Stealing</h3>
<ul>
<li>job의 개수가 낮은 큐: source queue</li>
<li>다른 target queue들에 훨씬 많은 수의 작업이 있는지 가끔씩 검사한다.</li>
<li>target queue가 source queue보다 훨씬 많이 차있으면, source queue가 작업을 가져온다.</li>
<li>문제:<ul>
<li>큐 자주 검사 -&gt; overhead 발생 -&gt; 확장성 저하</li>
<li>큐 자주 검사 안하면 -&gt; load imbalance 문제 해결 못함.</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[9. Scheduling: Proportional Share]]></title>
            <link>https://velog.io/@na_itsso/9.-Scheduling-Proportional-Share</link>
            <guid>https://velog.io/@na_itsso/9.-Scheduling-Proportional-Share</guid>
            <pubDate>Wed, 16 Oct 2024 12:23:49 GMT</pubDate>
            <description><![CDATA[<p>앞선 스케쥴링과 다른 &#39;fairness&#39; 관점에서 생각해보자</p>
<h1 id="9-fair-share-scheduler">9. Fair share scheduler</h1>
<ul>
<li>CPU time의 일정 비율대로 각 job이 할당 받는 것이 보장됨.</li>
<li>= Proportional Share(비례배분!)</li>
<li>turnaround time 과 response time은 optimized 되지 않음</li>
<li>ex ) Lottery scheduling / Stride scheduling / Completely Fair schedulig(Nice,vruntime, timeslice, red-black tree)<h2 id="91-lottery-scheduling">9.1 Lottery scheduling</h2>
<h3 id="basic-concept-추첨권이-당신의-지분이다">Basic Concept-추첨권이 당신의 지분이다.</h3>
<h4 id="tickets-하나의-process가-받는-resource의-비율-단위">Tickets: 하나의 process가 받는 resource의 비율 단위</h4>
</li>
<li>tickets의 비율이 시스템 리소스의 할당 비율</li>
<li>process가 가진 티켓 수에 따라 해당 자원을 나눠가짐.</li>
<li>ex) 프로세스 A가 75개의 티켓을 가지고 있으면, <strong>CPU 시간의 75%</strong></li>
<li>프로세스 B가 25개의 티켓을 가지고 있으면, <strong>CPU 시간의 25%</strong>를 차지하도록 목표한다.</li>
</ul>
<h3 id="방법-초-간단">방법 초 간단.</h3>
<ul>
<li>스케줄러는 winnig ticket을 뽑는다.(난수)<ul>
<li>해당 process를 로드하고, run 한다. <h3 id="example">Example<img src="https://velog.velcdn.com/images/na_itsso/post/6a40f833-2e5a-4dbd-ace8-68f62cf4db4d/image.png" alt=""></h3>
</li>
</ul>
</li>
<li>해당 job들이 더 길게 경쟁할 수록, 그들이 기대하던 percentage와 가까워진다. 만약에 job들의 실행수가 적으면, 비율대로 실행이 안될 수도 있다.</li>
<li>무작위성을 기반으로 하므로, 원하는 비율을 정확히 보장하지느 않는다. 장시간 실행하면 원하는 비율 달성 가능성 높아진다.</li>
<li>처음엔 랜덤한 결과로 보이지만, 시간이 지날수록 각 프로세스가 받은 티켓 수에 비례하여 자원을 사용하는 비율이 점차 목표 비율(75% vs 25%)에 가까워짐.</li>
<li>turnaround, response time 최적화 x </li>
<li>short ,long job 고려 x<h2 id="92-ticket-mechanisms">9.2 Ticket Mechanisms</h2>
<h3 id="1-ticket-currency티켓-통화">1) Ticket Currency(티켓 통화)</h3>
: 사용자가 각 프로세스나 작업에 자신만의 방식으로 티켓을 할당하고, 시스템이 이를 <strong>전역 티켓 수(Global currency)</strong>로 변환하는 방식<img src="https://velog.velcdn.com/images/na_itsso/post/b98b1446-b0df-4fb5-9e93-8d67af617c40/image.png" alt=""></li>
<li>A1: 100 * (500/1000)</li>
<li>A2: 100 * (500/1000)</li>
<li>B1: 100 * (10/10)<h3 id="2-ticket-transfer티켓-양도">2) Ticket transfer(티켓 양도)</h3>
: 자기가 당장 자원이 필요하지 않으면,** 일시적으로** 다른 프로세스에게 티켓 나눠주기</li>
<li>ex) client가 server에게 ticket transefer(나중에 환수)<h3 id="3-ticket-inflation티켓-인플레이션">3) Ticket Inflation(티켓 인플레이션)</h3>
: 자기 소유 티켓의 수를 임시적으로 증가시키거나 감소시키기</li>
<li>만약 특정 프로세스가 더 많은 CPU 시간을 필요하면, 티켓수를 스스로 일시적으로 증가 시킨다.<h2 id="93-implementation">9.3 Implementation <img src="https://velog.velcdn.com/images/na_itsso/post/32a5acf8-d4fd-4c6c-916b-913ae6a25df3/image.png" alt=""></h2>
</li>
<li>프로세스 및 티켓:<ul>
<li>Job A는 100개의 티켓</li>
<li>Job B는 50개의 티켓</li>
<li>Job C는 250개의 티켓</li>
<li>총 티켓 수는 400개야 (100 + 50 + 250).</li>
</ul>
</li>
<li>목록 순서: 프로세스는 티켓 수에 따라 연결 리스트로 관리됨. </li>
<li>코드 설명:<ul>
<li>랜덤 티켓 추출 (getrandom 함수): getrandom(0, totaltickets)에서** 0과 총 티켓 수(400) 사이에서 무작위로 티켓 번호가 선택**됨. 예를 들어, 150번 티켓이 선택될 수 있어.</li>
<li>반복문 (while 루프): <strong>선택된 티켓 번호에 해당하는 프로세스</strong>를 찾기 위해 리스트를 순차적으로 탐색함.<ul>
<li>counter는 현재까지 확인한 티켓 수를 누적.</li>
<li>현재 프로세스의 티켓 수를 counter에 더하고, counter가 winner 값(랜덤으로 선택된 티켓 번호)을 초과하면 그 프로세스가 선택됨.</li>
<li>예를 들어, winner가 123이라면 Job A와 Job B를 합쳐 150(즉, Job B가 포함된 시점) Job B가 선택됨.</li>
</ul>
</li>
</ul>
</li>
<li>주의: 최악의 경우 리스트 끝까지 탐색해야 하는 상황이 있을 수 있음. Job C가 선택되려면 끝까지 가야 함. 
  -&gt; 정렬: 티켓 수에 따라 미리 프로세스가 내림차순 정렬하기(이 작업은 한 번만 처리되는 오버헤드임)<h2 id="94-lottery-fairness-study">9.4 Lottery Fairness Study</h2>
<h3 id="u-unfairness-metric--first-job-completed-시간--second-job-completed-시간">U: unfairness metric = (first job completed 시간) / (second job completed 시간)</h3>
<ul>
<li>실행시간(run time): A : 10, B : 10</li>
<li>끝난시간(finish time): A : 10, B : 20</li>
<li>U = 1.0 / 2.0 = 0.5 </li>
<li>U가 1에 가까울 수록 fair하다.(거의 동시에 끝난다)<h3 id="lottery-scheduler-문제-fairness-problem">Lottery scheduler 문제: Fairness Problem<img src="https://velog.velcdn.com/images/na_itsso/post/d4fbaeb8-b5eb-4513-8983-c853b03a34d6/image.png" alt=""></h3>
</li>
</ul>
</li>
<li>각 job들이 모두 같은 티켓 가지고 있는 예시이다. </li>
<li>job length가 짧은 처음에는 unfair 할 수 있으나, 길어질수록 fair함.<h4 id="작업-길이가-그리-길지-않을-때-평균-불공정성average-unfairness이-상당히-심각할-수-있다">작업 길이가 그리 길지 않을 때, 평균 불공정성(average unfairness)이 상당히 심각할 수 있다.</h4>
</li>
</ul>
<h2 id="95-solution-deterministic-approach-stride-scheduling">9.5 Solution: Deterministic Approach: Stride Scheduling</h2>
<p>: 무작위성을 이용하면 단순하게는 가능하지만 정확한 비율 보장을 못하므로 결정론적으로!!
: 우선순위가 높으면 -&gt; 티켓 많음 -&gt; 보폭 적음 -&gt; 조금씩 진행 되므로, 강강약약인 OS는 기회를 더 줌.
: pass value(+=stride)가 가장 적은 process를 schedule시킨다.</p>
<h3 id="stride-of-each-process">Stride of each process</h3>
<ul>
<li>(large number) / (the number of tickets of the process)</li>
<li>자신이 가지고 있는 추첨권 수에 반비례</li>
<li>Example: large number = 10,000<ul>
<li>Process A has 100 tickets -&gt; stride of A is 100</li>
<li>Process B has 50 tickets -&gt; stride of B is 200<h3 id="counterpassvalue">Counter(=passvalue)</h3>
: 각 process마다 0에서 시작하여 run할때마다, 각 프로세스의 stride를 더한다. 
: 얼마나 CPU를 사용하였는지 추적 용도<img src="https://velog.velcdn.com/images/na_itsso/post/971bc9a0-8fd5-4059-a4bc-8b5729d74009/image.png" alt=""><h3 id="stride-scheduling-exampleimp">Stride Scheduling Example(imp) <img src="https://velog.velcdn.com/images/na_itsso/post/c3eb63da-31ec-41ee-9e38-f2722ada4a54/image.png" alt=""><img src="https://velog.velcdn.com/images/na_itsso/post/ae3f4fe4-ad72-421e-a159-46953fbb733e/image.png" alt=""></h3>
<h3 id="problem1-각-process마다-pass-value를-유지해야한다">Problem1: 각 process마다 pass value를 유지해야한다.</h3>
<h3 id="problem2-새로운-job이-pass-value-0으로-새로-들어오면-기존-다른-어떤-process-보다-pass-value가-작으므로-cpu를-독점할-것이다">Problem2: 새로운 job이 pass value 0으로 새로 들어오면, 기존 다른 어떤 process 보다 pass value가 작으므로, CPU를 독점할 것이다.</h3>
<h4 id="stride-scheduling-vs-lottery-scheduling">Stride Scheduling vs Lottery Scheduling</h4>
</li>
</ul>
</li>
<li>stride scheduling: fairness 보장(짧은 길이의 job이더라도)</li>
<li>lottery scheduling: no per process-state (overhead x)</li>
</ul>
<h2 id="97-the-linux-completely-fair-schedulingcfs">9.7 The Linux Completely Fair Scheduling(CFS)</h2>
<ul>
<li>non-fixed timeslice<ul>
<li>CPU의 사용 비율로 할당</li>
</ul>
</li>
<li>priority - <strong>nice value</strong> 사용<ul>
<li>덜 nice 할수록, 우선순위 높아지게 weight 크다.</li>
<li>더 nice 일수록, 우선순위 낮아지게 weight 작다.</li>
</ul>
</li>
<li>efficient data structure<ul>
<li>use red-black tree(효율적인 검색, 삽입, 삭제)<h3 id="1-basic-virtual-runtimevruntime">1) (basic) Virtual runtime(vruntime)</h3>
<ul>
<li>프로세스가 실제로 실행된 시간(프로세스마다 별도 관리)</li>
<li><strong>vruntime이 가장 낮은 프로세스를 스케쥴러가 선택</strong>한다.</li>
<li>CPU 자원의 공정한 배분을 도와준다.</li>
<li>process가 얼마만큼 CPU 썼는지 추적한다.<h3 id="2-sched_latency지연시간">2) Sched_latency(지연시간)</h3>
</li>
<li>스케줄러가 프로세스에게 CPU를 할당하기 위한 기본적인 지연 시간을 의미해. 일반적으로 이 값은 48밀리세컨드(millisecond)로 설정</li>
<li>공정하게 CPU 자원을 할당받을 수 있도록 타임슬라이스가 결정되며, 프로세스 수가 많아질수록 각 프로세스가 받을 수 있는 CPU 시간은 줄어듦<h3 id="3-basic-time-slice--sched_latency--실행-중인-프로세스의-수">3) (basic) Time Slice = sched_latency / (실행 중인 프로세스의 수)</h3>
<h3 id="example-1">Example<img src="https://velog.velcdn.com/images/na_itsso/post/e02f7403-c10c-4bb5-a6b1-a05e11cf813f/image.png" alt=""></h3>
</li>
</ul>
</li>
</ul>
</li>
<li>timeslice = 48/4=12ms -&gt; 48/2 = 24ms</li>
<li><strong>min_granularity</strong>: <strong>CPU 프로세스에 할당되는 최소 타임슬라이스</strong><ul>
<li>만약에 time slice가 6ms보다 작으면 그냥 6ms 보장</li>
<li>왜냐하면, 프로세스 수가 많을 경우, 스케줄러는 각 프로세스의 상태를 관리하고 CPU를 할당하기 위해 지속적으로 작업해야한다. 이때 너무 짧은 타임슬라이스를 설정하면 스케줄링에 소요되는 오버헤드가 증가한다.</li>
<li>이거 때문에 완전 complete fairness를 보장하는 건 아님...</li>
</ul>
</li>
</ul>
<h3 id="4-weight-nice-value">4) Weight-Nice Value</h3>
<h4 id="nice-value">Nice Value</h4>
<ul>
<li>CFS가 priority을 조정할 수 있게 한다.</li>
<li>Nice vlaue: -20 ~ 19 정수<ul>
<li>-20: 가장 높은 우선순위 (덜 나이스 할수록 더 많이 CPU 할당)</li>
<li>+19: 가장 낮은 우선순위 (더 나이스 할수록 덜 CPU 할당)</li>
</ul>
</li>
<li>nice value # weight (mapping)<ul>
<li>nice 낮을 수록, weight 높다.<img src="https://velog.velcdn.com/images/na_itsso/post/078e67f7-e87c-4685-8f2b-26131384fe73/image.png" alt=""><h3 id="5-weighting가중치-niceness">5) Weighting=가중치 (Niceness)</h3>
<h3 id="new-timeslice-with-weight">(new) Timeslice with weight</h3>
<img src="https://velog.velcdn.com/images/na_itsso/post/7f5285f8-6c04-44ef-b1cc-cb007608bbc7/image.png" alt=""></li>
</ul>
</li>
<li>프로세스의 우선순위 차이까지도 고려한 timeslice이다.</li>
</ul>
<h3 id="new-vruntime-with-weight">(new) Vruntime with weight<img src="https://velog.velcdn.com/images/na_itsso/post/f1966406-7b33-4d5b-ae0a-1c441c8681a1/image.png" alt=""></h3>
<p>: vruntime += nicevalue의 중간값 weight(0) / 내 weight * runtime</p>
<ul>
<li>실행시간 누적하는 것 뿐만 아니라 우선순위 차이까지도 고려한다.</li>
<li>weight 높을수록, vruntime 작아져서 먼저 실행된다.(stride로 나누듯이 weight로 나누기)</li>
</ul>
<p>---&gt; 가중치 표의 장점은 nice값의 차이가 유지되면, CPU 배분 비율도 유지된다.</p>
<h3 id="structure-of-ready-queue-red-black-tree">Structure of ready queue: Red-Black Tree<img src="https://velog.velcdn.com/images/na_itsso/post/f6da0368-3064-4516-8834-a7f074cad3a8/image.png" alt=""></h3>
<ul>
<li>balanced binary tree</li>
<li>ordering : O(logn)</li>
<li>최소 vruntime process을 효율적으로 찾을 수 있다.</li>
<li>오직 running(runnable O, sleep X, blocked X)중인 process들만 tree에 있다.</li>
</ul>
<h3 id="ioblocked-and-sleepingsemaphore-api-process-">I/O(blocked) and Sleeping(semaphore, api) Process ?</h3>
<ul>
<li>문제: process가 sleep 하는 동안은 vruntime이 증가하지 않아, 매우 작아집니다. 매우 작아진 프로세스가 다시 CPU 사용하게 되면, CPU를 독점하여 과도하게 차지할 수 있습니다. </li>
<li>해결: 프로세스가 다시 깨어날 때, 해당 프로세스의 vruntime을 현재 트리에서 발견된 최솟값으로 설정합니다. </li>
<li>그러나, Process that sleep for short periods of time frequently do not ever get their fair share of the CPU.(왜??)</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[8. Scheduling: Multi-Level Feedback Queue(MLFQ)]]></title>
            <link>https://velog.io/@na_itsso/8.-Scheduling-Multi-Level-Feedback-QueueMLFQ</link>
            <guid>https://velog.io/@na_itsso/8.-Scheduling-Multi-Level-Feedback-QueueMLFQ</guid>
            <pubDate>Wed, 16 Oct 2024 10:16:31 GMT</pubDate>
            <description><![CDATA[<h1 id="review">Review</h1>
<h3 id="fifo-algorithm">FIFO algorithm</h3>
<ul>
<li>convoy effect(tractor가 길을 다 막는다) -&gt; low CPU 와 device utilization<h3 id="sjfshortest-job-first-scheduling-algorithm">SJF(Shortest Job First) scheduling algorithm</h3>
</li>
<li>*<em>평균 turnaround time(terminate-arrival)을 줄인다. *</em></li>
<li><strong>평균 waiting time(start-arrival)을 줄인다.</strong></li>
<li>job length를 미리 알 수 있는가? 항상 좋은가?<h3 id="rr-scheduling-algorithm">RR scheduling algorithm</h3>
</li>
<li><strong>response time 줄인다.</strong>(각 프로세스마다 정해진 타임 퀀텀 동안 번갈아가며 CPU 할당)</li>
<li><strong>turnaround time</strong>을 줄이지는 못한다. <h3 id="need-a-new-algorithm-for">Need a new algorithm for</h3>
</li>
<li>optimize turnaround time -&gt; run shortest job first</li>
<li>minimize response time -&gt; use Round Robin to 가능한 많은 job 실행 (반응성=first run - arrival)</li>
<li>Learn from the past to predict the future without prior knowledge of job length</li>
</ul>
<h1 id="8-scheduling-multi-level-feedback-queuemlfq">8. Scheduling: Multi-Level Feedback Queue(MLFQ)</h1>
<h2 id="81-basic-rules">8.1 Basic Rules</h2>
<ul>
<li><strong>다른 priority level들로 구성된 queues</strong>들을 가진다.</li>
<li><strong>하나의 job은 하나의 queue</strong>에서 실행된다.<h3 id="rule-1-다른-큐끼리-higher-queue에-있는-job이-우선적으로-실행된다">Rule 1: 다른 큐끼리) higher queue에 있는 job이 우선적으로 실행된다.</h3>
<h3 id="rule-2-같은-큐끼리-round-robin-스케쥴링을-사용하여-실행한다정해진-타임-퀀텀-끝나면-다른-job">Rule 2: 같은 큐끼리) Round Robin 스케쥴링을 사용하여 실행한다.(정해진 타임 퀀텀 끝나면 다른 job)</h3>
</li>
<li><strong>작업의 관찰된 행동</strong>에 따라 우선순위를 조정합니다.<ul>
<li>작업이 반복적으로 <strong>CPU를 포기하고 입출력(I/O)을 기다리면</strong>, 우선순위를 <strong>높게</strong> 유지해.</li>
<li>반면, 작업이 오랜 시간 동안 <strong>CPU를 집중적으로 사용하면</strong>, 그 작업의 우선순위를 <strong>낮춘</strong>다.<img src="https://velog.velcdn.com/images/na_itsso/post/8080afea-e998-4902-a37f-26bd2aff7af9/image.png" alt=""></li>
</ul>
</li>
</ul>
<h2 id="82-how-to-change-priority">8.2 How to Change Priority</h2>
<h3 id="rule-3-처음에-system에-job이-들어올-때-가장-높은-priority-queue에-위치한다">Rule 3: 처음에 system에 job이 들어올 때, 가장 높은 priority queue에 위치한다.</h3>
<h3 id="rule-4a-실행중에-모든-time-slice를-사용하면-해당-job이-priority는-감소한다">Rule 4a: 실행중에 모든 time slice를 사용하면, 해당 job이 priority는 감소한다.</h3>
<h3 id="rule-4b-모든-time-slice을-사용하기-전에-job이-cpu를-놓으면-계속-해당-priority-level을-유지한다">Rule 4b: 모든 time slice을 사용하기 전에 job이 CPU를 놓으면, 계속 해당 priority level을 유지한다.</h3>
<p>--&gt; 이러한 방식으로 <strong>Shortest Job First</strong>에 근사한다. 
왜냐하면, 4a: CPU을 집중적으로 사용하는, 오래 걸리는 job이므로 우선순위를 낮추어 나중에 실행하게 한다. 
4b: CPU를 조금 쓰고 스스로 놓는 경우, short job이므로 높은 우선순위 유지
-&gt; <strong>turnaround time 평균 줄이기, fairness 추가(?)</strong>
  <img src="https://velog.velcdn.com/images/na_itsso/post/184bb69b-3cc2-443c-9659-7779f43a33b1/image.png" alt=""> -&gt; 낮은 우선순위 계속 실행 못할 수도 있으므로 priority boost 추후 사용</p>
<h4 id="example-1-한개의-긴-실행시간-가진-작업">Example 1: 한개의 긴 실행시간 가진 작업</h4>
<p><img src="https://velog.velcdn.com/images/na_itsso/post/5e6249e4-3cb7-45c3-a0fa-421f6c6f3014/image.png" alt=""> 처음 시스템에 들어올 때 가장 높은 우선순위 큐에 위치하지만, 10ms 안에 CPU를 놓지 않으므로 계속해서 더 낮은 priority 큐로 강등된다. </p>
<h4 id="example-2-짧은-작업과-함께-가장-먼저-시스템에-들어온-a는-가장-priority-높은-q2에서-시작하지만-앞선-예시와-같은-이유로-강등된다-그후-b가-들어오고-b도-20ms-동안-실행하므로-강등된다-그렇지만-a보다는-높아서-먼저-실행된다">Example 2: 짧은 작업과 함께 <img src="https://velog.velcdn.com/images/na_itsso/post/0d26e2c7-ae4f-4e03-a6bb-b451a23edfc7/image.png" alt="">가장 먼저 시스템에 들어온 A는 가장 priority 높은 Q2에서 시작하지만, 앞선 예시와 같은 이유로 강등된다. 그후 B가 들어오고 B도 20ms 동안 실행하므로 강등된다. 그렇지만 A보다는 높아서 먼저 실행된다.</h4>
<h4 id="example-2-입출력-작업--b는-cpu를-매우-짧게-사용하여-10ms안에-스스로-놓기-때문에-강등되지-않고-io-작업을-수행한다-그리고-cpu는-b의-io-작업이-끝나고-나서-b가-ready-queue로-들어가므로-다시-또-짧은-job인-b가-실행-될-수-있도록-한다">Example 2: 입출력 작업 <img src="https://velog.velcdn.com/images/na_itsso/post/fbe036f7-5ee1-4766-bea5-ea7ba0342bf2/image.png" alt=""> B는 CPU를 매우 짧게 사용하여, 10ms안에 스스로 놓기 때문에 강등되지 않고 I/O 작업을 수행한다. 그리고 CPU는 B의 I/O 작업이 끝나고 나서 (B가 ready queue로 들어가므로) 다시 또 짧은 job인 B가 실행 될 수 있도록 한다.</h4>
<p>-&gt; 세 경우 모두 작업이 짧은 작언인지 긴 작업인지 알 수 없어도 먼저 짧다고 가정 후 우선순위를 조정하며 SJF 에 근사한다.</p>
<h2 id="problems-with-the-basic-mlfq">Problems with the Basic MLFQ</h2>
<h3 id="1-starvation">1) Starvation</h3>
<ul>
<li>interactive(대화형) jobs들이 많으면, 계속 해당 job들만 실행되므로, long running job들이 CPU를 할당 받지 못한다. <h3 id="2-game-the-scheduler">2) Game the scheduler</h3>
</li>
<li>만약, time slice의 99%만 사용하고, I/O operation 을 수행하는 job이 있다고 가정하자. 이 job은 time slice를 다 사용하기 거의 직전에 스스로 CPU를 놓으므로 계속 높은 priority을 유지한다. 그렇지만 계속해서 CPU를 거의 다 사용하여 독점현상이 발생한다.<h3 id="3-a-program-may-change-its-behavior-over-time">3) A program may change its behavior over time</h3>
</li>
<li>CPU bound process였다가 I/O bound process로 바뀔 수도 있다. 이때 다시 우선순위가 높아지는 mechanism이 필요하다. <h2 id="p2-solution-better-accounting">P2-Solution: Better Accounting</h2>
<h3 id="rule-4-한-작업이-주어진-레벨우선순위-큐에서-할당된-시간time-allotment을-모두-사용하면-몇-번이나-cpu를-포기했는지에-상관없이-그-작업의-우선순위가-낮아진다즉-큐에서-아래로-이동한다-입출력-중점-대화형-작업을-빨리-실행시킨다">Rule 4: 한 작업이 주어진 레벨(우선순위 큐)에서 할당된 시간(time allotment)을 모두 사용하면, (몇 번이나 CPU를 포기했는지에 상관없이), 그 작업의 우선순위가 낮아진다(즉, 큐에서 아래로 이동한다). 입출력 중점 대화형 작업을 빨리 실행시킨다.</h3>
이 규칙은 작업이 특정 우선순위 큐에서 CPU 시간(time allotment)을 다 소모하면, 더 낮은 우선순위로 이동하게 된다.</li>
</ul>
<h2 id="p1p3-solution-the-priority-boost">P1,P3-Solution: The Priority Boost</h2>
<h3 id="rule-5-some-time-period-s-이후엔-모든-job들을-가장-높은-우선순위-큐로-옮긴다">Rule 5: some time period S 이후엔, 모든 job들을 가장 높은 우선순위 큐로 옮긴다.<img src="https://velog.velcdn.com/images/na_itsso/post/196efeaf-1108-4165-8617-724d48efce84/image.png" alt=""></h3>
<h2 id="tuning-mlfq-and-other-issues">Tuning MLFQ And Other Issues</h2>
<p>-&gt; Lower Priority, Longer Quanta</p>
<ul>
<li>우선순위가 높은 큐 -&gt; short time slice</li>
<li>우선순위가 낮은 큐 -&gt; long time slice<img src="https://velog.velcdn.com/images/na_itsso/post/17692560-f20d-4bf3-9fa9-12035c105beb/image.png" alt=""><h2 id="the-solaris-mlfq-implementation">The Solaris MLFQ Implementation</h2>
</li>
<li>60개 queue를 가진다.</li>
<li>낮은 우선순위 : 수백 milliseconds</li>
<li>높은 우선순위 : 20msec(빨리 빨리 response time 반응성)</li>
<li>1s 마다 우선순위 boost!</li>
</ul>
<p>--&gt; 프로세스의 CPU 사용에 대한 이전 지식이 필요하지 않는다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[5. Process API]]></title>
            <link>https://velog.io/@na_itsso/5.-Process-API</link>
            <guid>https://velog.io/@na_itsso/5.-Process-API</guid>
            <pubDate>Fri, 04 Oct 2024 05:02:47 GMT</pubDate>
            <description><![CDATA[<p>fork, exec, wait 와 I/O redirection, pipe</p>
<h2 id="fork">fork()</h2>
<ul>
<li>자식 process 생성</li>
<li>부모의 address space copy<img src="https://velog.velcdn.com/images/na_itsso/post/344a584c-8506-4a7c-936e-8b60323f226b/image.png" alt=""><h2 id="wait-or-waitpid">wait() or waitpid()</h2>
</li>
<li>child와 parent 간의 dependency 생성(deterministic)</li>
<li>reaping a child process</li>
<li>자식 process가 종료되면, exit(status)을 report 하도록 한다. </li>
<li>자식의 exit status는 process table에 저장되고, process table의 entry는 parent process 가 wait call을 invoke 한 뒤 해제된다. </li>
<li>wait()가 호출되면 부모 프로세스는 <strong>자식의 종료 상태를 받아들이고</strong>, 그 후 <strong>자식 프로세스의 프로세스 테이블 항목(PCB)은 운영체제에 의해 할당 해제</strong>됩니다.
이를 통해 좀비 프로세스(종료 후 아직 reaping 되지 않은 자식)가 정리되고, 
프로세스 테이블에 남은 항목이 제거됩니다. (자식 프로세스에 대한 모든 참조가 삭제됨을 의미합니다.)<img src="https://velog.velcdn.com/images/na_itsso/post/8c5dc6bc-aa6a-40ea-b9dc-76094f6409ff/image.png" alt=""><h4 id="zombie-process">Zombie Process</h4>
</li>
<li>process 실행은 다 완수했지만, process table에 남아있는 process</li>
<li>부모는 executing, while child is dead.<h4 id="orphan-process">Orphan Process</h4>
</li>
<li>parent가 wait 하지 않은 상태로 죽었는데, 실행중인 child process</li>
<li>init process가 새로운 부모가 되고, wait call을 호출한다.</li>
<li>본래 부모는 dead, while child is executing</li>
</ul>
<h2 id="does-fork-immediately-copy-the-entire-process-heap-in-linux---no">Does fork() immediately copy the entire process heap in Linux? - NO</h2>
<h3 id="copy-on-write-방식-사용">Copy-On-Write 방식 사용<img src="https://velog.velcdn.com/images/na_itsso/post/3f7edcf4-609f-4b47-bc9c-fecfebea91b0/image.png" alt=""></h3>
<ul>
<li>기본 동작:<ul>
<li>fork()를 호출하면 부모 프로세스의 메모리 공간(코드, 데이터, 힙 등)을 자식 프로세스와 공유합니다. </li>
<li>하지만 실제로는 메모리를 복사하지 않고, 두 프로세스가 같은 메모리 페이지를 참조합니다.</li>
</ul>
</li>
<li>메모리 페이지 수정 시점:<ul>
<li>부모 프로세스나 자식 프로세스 중 하나가 메모리를 수정하려고 할 때, 해당 페이지가 복사됩니다.</li>
<li>최초로 수정하려는 시점에만 복사가 이루어지며, 이때 각 프로세스는 독립적인 메모리 공간을 갖게 됩니다.</li>
</ul>
</li>
</ul>
<h2 id="exec">exec()</h2>
<p>: running a new program</p>
<ul>
<li>parent 코드 말고 다른 코드 실행하고 싶어!</li>
<li>운영체제는 새로운 프로그램(바이너리 이미지)을 메모리에 로드하고, 새 프로그램을 위한 스택 및 힙을 초기화합니다.</li>
<li>인자: (실행할 바이너리 파일의 경로, 해당 프로그램에 전달할 인자 배열 argv)</li>
<li>1번) 현재 프로세스의 내용을 지우고 2번)새로운 프로그램의 내용을 메모리에 로드하여 새로운 프로그램을 실행시키는 역할을 합니다.(pid는 유지)(현재 실행중인 process 덮어씌우기)</li>
<li>return 값 없다.<img src="https://velog.velcdn.com/images/na_itsso/post/b3c97b69-2017-4101-98e8-0f4c30a1fa0c/image.png" alt=""></li>
<li>ex) <img src="https://velog.velcdn.com/images/na_itsso/post/4ffff4e1-1b16-4c13-af92-85777214747c/image.png" alt=""></li>
</ul>
<ul>
<li><p>kernel에서 제공하는 API를 가지고 process 실행</p>
</li>
<li><p>fork 와 exec 구분하는 이유? </p>
</li>
<li><blockquote>
<p>실행 전에 I/O redirection 또는 pipe를 중간에 사용하려고<img src="https://velog.velcdn.com/images/na_itsso/post/ab1c71ba-48f3-4470-9cfd-560aa1ccddcd/image.png" alt=""></p>
</blockquote>
</li>
<li><p>I/O redirection : 앞의 outcome이 stdout이 아니라 뒤에 있는 파일로 가도록해준다.</p>
</li>
<li><p>pipe: 앞의 outcome이 뒤의 입력으로 가도록 해준다. 
서로 address 공간이 달라서 원래는 접근이 불가능하지만, OS가 Inter Process Communication을 제공한다. (I/O redirection, pipe)<img src="https://velog.velcdn.com/images/na_itsso/post/b4192fc7-e2d5-4edb-9875-4278a5882b27/image.png" alt=""></p>
</li>
</ul>
<h2 id="io-redirection">I/O redirection</h2>
<p>: 전자의 output을 capture하여 후자의 input으로 send한다.<img src="https://velog.velcdn.com/images/na_itsso/post/07e26a57-f0b9-4890-80dd-2f8c08f0789f/image.png" alt=""> <img src="https://velog.velcdn.com/images/na_itsso/post/681edd7a-72ee-4fc7-ada1-380147aa36b4/image.png" alt=""><img src="https://velog.velcdn.com/images/na_itsso/post/c4fcac10-42e4-4cac-9e8e-31de95dea7ba/image.png" alt=""><img src="https://velog.velcdn.com/images/na_itsso/post/034d8eff-37b0-4782-9c6d-6a4f15778443/image.png" alt=""></p>
<h3 id="file-descriptor-and-file-descriptor-table">File Descriptor and File Descriptor Table</h3>
<ul>
<li>process가 생성되면, process의 file descriptor array를 만든다.</li>
<li>STDIN, STDOUT, STDERR는 초기화 되어있다.</li>
<li>File Descriptor -&gt; File Struct(각 struct마다 offset 존재)</li>
<li>ex) read 시스템 콜 하게되면, kernel이 해당 fd가 가리키는 struct의 offset을 읽고 buffer에 복사한다.</li>
<li>ex) write 시스템 콜 하게되면, kernel이 buffer에 있는 내용을 해당 fd가 가리키는 struct의 offset에 이어서 쓴다.<img src="https://velog.velcdn.com/images/na_itsso/post/a9d939c1-e882-495b-af36-d366cdceb150/image.png" alt=""><img src="https://velog.velcdn.com/images/na_itsso/post/904e3dd8-6c66-4565-9104-0ada3af8a4dd/image.png" alt=""> <img src="https://velog.velcdn.com/images/na_itsso/post/39043f56-9bc0-42f5-998f-d3f6b155e8fc/image.png" alt=""></li>
</ul>
<h3 id="file-descriptor-and-system-calls">File Descriptor and System Calls</h3>
<ul>
<li>open(): 
새로운 파일을 열 때, 운영체제는 새로운 파일 객체를 할당하고, 이를 가리키는 <strong>FD</strong>를 생성합니다. 이 파일 디스크립터는 파일 디스크립터 테이블에서 사용 가능한 가장 작은 번호를 할당받습니다.  </li>
<li>close(): <ul>
<li><strong>파일 디스크립터 fd</strong>가 더 이상 사용되지 않도록 해제합니다.</li>
<li>해당 파일 디스크립터와 연결된 <strong>파일 객체</strong>가 <strong>더 이상 어떤 파일 디스크립터에서도 참조되지 않으면</strong>, 그 파일 객체도 메모리에서 해제됩니다.</li>
</ul>
</li>
<li>fork(): <ul>
<li>부모의 fd table을 자식에게 copy합니다.(file struct 공유)</li>
</ul>
</li>
<li>exec():<ul>
<li>프로세스가 파일 디스크립터 테이블을 유지한다. <img src="https://velog.velcdn.com/images/na_itsso/post/7c6acc6a-03c4-4d60-a8be-b1226f69d853/image.png" alt=""><img src="https://velog.velcdn.com/images/na_itsso/post/5484a28c-7d2b-46db-b9d3-b455c4713e61/image.png" alt=""> <img src="https://velog.velcdn.com/images/na_itsso/post/27f14de3-70e1-4fad-b252-2f8c19a70e2b/image.png" alt=""> <img src="https://velog.velcdn.com/images/na_itsso/post/95646e34-96a8-4147-9188-7a30d47afb6d/image.png" alt=""> <img src="https://velog.velcdn.com/images/na_itsso/post/8871ee48-3226-4f12-bd37-b49a32449065/image.png" alt=""> <img src="https://velog.velcdn.com/images/na_itsso/post/ca8dfd44-5747-48f7-aa4a-549c33087e0b/image.png" alt=""> <img src="https://velog.velcdn.com/images/na_itsso/post/3f272312-aa68-444d-8ed1-d5d5f74beb29/image.png" alt=""><h2 id="pipe-">Pipe: &#39;|&#39;</h2>
: 한 process의 output이 STDOUT이 다른 process의 STDIN으로 들어간다.</li>
</ul>
</li>
</ul>
<h3 id="duplication-of-fd-using-dup">Duplication of FD using dup()</h3>
<p>fd = dup(n) system call : file descriptor table의 빈 곳을 찾아 n을 복사한다. <img src="https://velog.velcdn.com/images/na_itsso/post/ddd82634-3ab2-46f2-8299-e02f25ea9f00/image.png" alt=""> </p>
<h3 id="pipe">pipe()</h3>
<p>: 커널에서 관리되는 특수한 파일(kernel buffer을 읽고 쓰는 fd)로, 두 개의 파일 디스크립터를 통해 프로세스 간에 데이터를 전달할 수 있습니다. 이 파일 디스크립터들은 읽기와 쓰기를 위한 각각의 끝을 나타냅니다.</p>
<ul>
<li><strong>파이프(pipe)</strong>는 단방향(unidirectional) 통신(FIFO queue)을 위해 사용됩니다.</li>
<li>한 쪽에서는 데이터를 쓰고, 다른 쪽에서는 그 데이터를 읽을 수 있습니다.
<img src="https://velog.velcdn.com/images/na_itsso/post/0e100991-26db-4893-abb7-49576b275f1c/image.png" alt=""> <img src="https://velog.velcdn.com/images/na_itsso/post/4bb10f72-e791-4d54-bdf3-da9429bab580/image.png" alt=""></li>
<li>No structured communication: 데이터의 크기나 송신자/수신자 정보를 알 수 없습니다.</li>
<li>파이프의 접근 방식은 <strong>파일 디스크립터(file descriptor)</strong>를 통해 이루어집니다.</li>
<li>파이프는 두 개의 파일 디스크립터로 구성됩니다:<h4 id="p0-읽기-끝-read-end">p[0]: 읽기 끝 (read end)</h4>
<ul>
<li>다른 프로세스는 <strong>p[0]</strong>을 통해 데이터를 읽습니다. </li>
<li>만약 읽을 데이터가 없으면, <strong>읽기 프로세스는 차단(block)</strong>되어 대기 상태가 됩니다.   </li>
<li>즉, 버퍼에 데이터가 쌓일 때까지 읽는 프로세스는 기다리게 됩니다.<h4 id="p1-쓰기-끝-write-end">p[1]: 쓰기 끝 (write end)</h4>
</li>
<li>한 프로세스가 <strong>p[1]</strong>을 통해 데이터를 쓰면, 그 데이터는 커널에서 관리하는 버퍼에 저장됩니다.</li>
</ul>
</li>
</ul>
<h3 id="pipe-used-by-commands">Pipe Used by Commands</h3>
<p>e.g., &gt; ps-aux | grep root | tail <img src="https://velog.velcdn.com/images/na_itsso/post/9957a027-aaf3-4003-adc0-869754525c26/image.png" alt=""></p>
<h3 id="anonymous-pipe">Anonymous Pipe</h3>
<p>int pipe(int filesdes[2])
: 프로세스가 파이프를 만들지만 실제로 누가 쓰고 읽는지 알 수 없다.
<img src="https://velog.velcdn.com/images/na_itsso/post/8bb3cd27-790c-4d6d-8aba-f916f5ce404c/image.png" alt="">
부모 process 는 fd[0]을 통해 읽고, fd[1]에다가 쓴다.
만약 fork를 하는 경우, 동일한 fd table 공유, 즉 동일한 pipe 공유
child process는 fd[0]을 통해 읽고, fd]1]에다가 쓴다.
따라서 parent의 close(fd[0]), child의 close(fd[1]) 하면 메모리 누수를 막는다.</p>
<h4 id="한계">한계</h4>
<p>두 개 프로세스가 커뮤니케이트 할 땐 좋지만,</p>
<ul>
<li>한개의 process가 communicate 끝난 다음에 다른 process가 communicate할 수 있다.</li>
<li>그리고 process가 여러개인 경우 누가 읽고 쓰는지 모른다.</li>
</ul>
<h3 id="named-pipefifo">Named Pipe(FIFO)</h3>
<ul>
<li>child-parent가 아닌 여러 process가 공유할 수 있게 해주는 pipe</li>
<li>mkfifo or mknod 명령어를 통해 생성된다.<ul>
<li>int mkfif (const char *paht, mode_T, mode);</li>
<li>file이라는 path를 통해서 kernel buffer을 연결 할 수 있게 만들어준다.</li>
<li>file path가 곧 kernel buffer에 대한 이름이다.
ex) <img src="https://velog.velcdn.com/images/na_itsso/post/8f9a141c-8f72-4537-8307-22c2c640507d/image.png" alt=""> </li>
<li>Write-Only without O_NONBLOCK(O_WRONLY): 파일을 쓰기 전용으로 열겠다.</li>
<li>읽기 프로세스가 대기 중인 경우: 쓰기 작업이 즉시 완료됩니다.</li>
<li>읽기 프로세스가 없는 경우: 쓰기 작업은 블로킹 상태가 되어 대기하게 됩니다.
<img src="https://velog.velcdn.com/images/na_itsso/post/3c5f70e9-644f-46c2-a425-7dab88273a97/image.png" alt=""></li>
<li>nmyfifo라는 kernel buffer가 할당됨</li>
<li>unlink() file-system call: 실제 file object delete하는 역할</li>
</ul>
</li>
</ul>
]]></description>
        </item>
    </channel>
</rss>