GameChoi
Choi Programming
GameChoi
전체 방문자
오늘
어제
  • 분류 전체보기 (468)
    • C++ Algorithm & Study (184)
      • C++ & Algorithm Strategies (45)
      • Game Math & DirectX 11 (72)
      • Server + UE5 (29)
      • Lyra Clone Coding (37)
    • Create Game (284)
      • [Window API] Game Client & .. (55)
      • [DirectX] DirectX 2D & 3D (155)
      • [UE5] BLUEPRINT & C++ (74)
    • odds and ends (0)
      • English (0)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • core
  • server
  • GAME Client
  • client
  • protobuf
  • Player State
  • job queue
  • c++
  • Direct11
  • session
  • Network Worker
  • Other Character
  • UE5
  • RPG Game
  • Game Room
  • Player Move Packet
  • Game Server
  • Direct3D
  • Algorithm Strategies
  • Destination Move Packet

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
GameChoi

Choi Programming

[Algorithm Strategies] 06. Divide & Conquer - Karatsuba Multipy
C++ Algorithm & Study/C++ & Algorithm Strategies

[Algorithm Strategies] 06. Divide & Conquer - Karatsuba Multipy

2023. 7. 14. 19:55

1. Divide & Conquer

1.1 Karatsuba Multipy - Example Program

1.1.1 Problem

- 빠른 곱셈 알고리즘으로, 두 개의 정수를 곱하는 알고리즘

   - 32비트 정수 둘을 곱할 때 쓰는 것이 아닌 수백자리, 나아가 수만 자리는 되는 큰 숫자들을 다룰 때 주로 사용

     - 이 곱셈 알고리즘을 적용하기 전 기존의 곱셈 알고리즘을 설명

1.1.1.1 O(n2) Mutiply

vector<int> DivideConquer::multiply(const vector<int>& a, const vector<int>& b);

 -  곱셈을 진행할 때 일반적인 정수형 변수가 아닌 정수형 배열을 입력받는 점을 확인

   - 이 배열들은 곱할 수의 각 자릿수를 맨 아래 자리부터 저장, 이렇게 순서를 뒤집으면 입출력할 때는 불편

     - 주어진 자릿수의 크기를 쉽게 구할 수 있다는 장점 존재

 - 따라서 C에 모든 값을 곱한 데이터 저장 및 Normalize 함수 실행

vector<int> c(a.size() + b.size() + 1, 0);
for (int i = 0; i < a.size(); i++) for (int j = 0; j < b.size(); j++) c[i + j] = a[i] * b[i];
normalize(c);

1.1.1.2 Normalize

void DivideConquer::normalize(vector<int>& num);

 - 1개의 값을 추가하여 반복문에 대해 초과되지 않게 설정하고 자릿수 올림 설정

num.push_back(0);
for (int i = 0; i + 1 < num.size(); i++) { /* ... */ }

   - 음수의 경우 앞의 자리수를 빌려 뒤에서 값을 사용할 수 있도록 설정

     - 양수의 경우 10보다 큰 경우의 수의 값이 들어올 경우 나눈 후 앞의 값에 더해주고 원래 값은 나머지 값으로 설정

if (num[i] < 0) { int borrow = (abs(num[i]) + 9) / 10; num[i + 1] -= borrow; num[i] += borrow * 10; }
else { num[i + 1] += num[i] / 10; num[i] %= 10; }

   - 배열의 마지막이 0인 경우 0을 빼고 반환

while (num.size() > 1 && num.back() == 0) num.pop_back();

1.1.2 Algorithm Strategy

- 카리츠바의 빠른 곱셈 알고리즘은 두 수를 각각 절반으로 쪼개 a와 b가 각각 256자리 수라면 128자리를 저장

   - a = a1 X 10128 + a0 & b = b1 X 10128 + b0

     - 카리츠바는 이 떄 a X b를 네 개의 조각을 이용해 표현

       - a X b = a1 X b1 X 10128 +(a1 X b0 + a0 X b1) X 10128 + a0 X b0

 - 이 방법에서 큰 정수 두 개를 한 번 곱하는 대신, 절반 크기로 나눈 작은 조각 네 번을 곱함

   - 이대로 각각을 재귀 호출해서 해결하면 분할 정복 알고리즘을 사용 가능

 - 카라츠바가 발견한 것은 다음과 같이 a X b를 표현했을 때 네 번 대신 세번의 곱셉으로 이 값을 계산

   - (a0 + a1) X (b0 + b1) = a0 X b0 + (a1 * b0 + a0 X b1) + a1 X b1

     - 위의 곱셈을 통해 두개를 곱하여 파란색의 값과 빨간색의 값을 빼면 값을 구할 수 있음

 - 따라서 이 과정의 곱셈을 세 번밖에 쓰지 않음, 세 결과를 적절히 조합해 원래 두 수의 답을 구해낼 수 있음

1.1.3 implementation

vector<int> DivideConquer::Karatsuba(const vector<int>& a, const vector<int>& b);

 - a가 b보다 크지 않는 경우만 활용할 수 있도록 설정하기 위해 큰 값이 있는 경우 변경하여 설정

   - 종료조건이 0이거나 50보다 작은경우 다른 것을 활용하거나 종료

int an = a.size(), bn = b.size(); if (an < bn) return Karatsuba(b, a);
if (an == 0 || bn == 0) return vector<int>(); if (an < 50) return multiply(a, b);

 - 위에서 설명했듯이 a0, a1, b0, b1를 생성하여 계산에 활용할 수 있도록 설정

   - 설정한 값을 이용하여 위에서 구한 3가지 곱셈 중 2가지를 활용할 수 있으므로 곱셈 진행

int half = an / 2;
vector<int> a0(a.begin(), a.begin() + half); vector<int> a1(a.begin() + half, a.end());
vector<int> b0(b.begin(), b.begin() + min<int>(b.size(), half));
vector<int> b1(b.begin() + min<int>(b.size(), half), b.end());

vector<int> z2 = Karatsuba(a1, b1); vector<int> z0 = Karatsuba(a0, b0);

   - (a0 + a1) X (b0 + b1)를 계산하여 위에서 곱한 2가지 값을 뺀 경우 마지막 한 조각인 마지막 값을 만들 수 있음

/* a += b * 10^k */ addTo(a0, a1, 0); addTo(b0, b1, 0);	
vector<int> z1 = Karatsuba(a0, b0);
/* a -= b */ subFrom(z1, z0); subFrom(z1, z2);

 - 마지막으로 모든 값을 더해주게 된다면 값을 구할 수 있음

vector<int> ret; addTo(ret, z0, 0); addTo(ret, z1, half); addTo(ret, z2, half + half);
저작자표시 (새창열림)

'C++ Algorithm & Study > C++ & Algorithm Strategies' 카테고리의 다른 글

[Algorithm Strategies] 05. Exhaustive Search - Clock Sync  (0) 2023.07.13
[Algorithm Strategies] 04. Exhaustive Search - Traveling Sale  (0) 2023.07.12
[Algorithm Strategies] 03. Exhaustive Search - Board Cover  (0) 2023.07.12
[Algorithm Strategies] 02. Exhaustive Search - Picnic  (0) 2023.07.11
[Algorithm Strategies] 01. Exhaustive Search - Boggle  (0) 2023.07.10
    'C++ Algorithm & Study/C++ & Algorithm Strategies' 카테고리의 다른 글
    • [Algorithm Strategies] 05. Exhaustive Search - Clock Sync
    • [Algorithm Strategies] 04. Exhaustive Search - Traveling Sale
    • [Algorithm Strategies] 03. Exhaustive Search - Board Cover
    • [Algorithm Strategies] 02. Exhaustive Search - Picnic
    GameChoi
    GameChoi

    티스토리툴바