Karatsuba Algorithm

Before Gettign Into Karatsuba Algorithm

예전에 대학원생일때, Addition, Subtraction, Division, Multiplication 에 관련되서 Project 로 작성한적이 있다. (어떻게하면 각 Operation 을 빠르게 할수 있는지에 대해서, Hardware 측면에서 더 이야기를 했던것 같아. Multiplexer 의 추가 등…)

그래서 일단 Addition / Subtraction / Multiplication 에 대한 예제코드를 봐보겠다. C++ 로 작성했으며, 항상 First Digit 이 Second Digit 의 길이가 크다라는 가정하에 작성을 했다. 자 특이점은 전부다 String 으로 처리한다는 점이다.

Addition

string Add(string str1, string str2)
{
	if (!str1.size() && !str2.size())
		return "0";

	int N = max(str1.size(), str2.size());
	str1 = string(N - str1.size(), '0') + str1;
	str2 = string(N - str2.size(), '0') + str2;

	string result(N, '0');
	int carry = 0;
	for (int i = N - 1; i >= 0; i--)
	{
		int n1 = str1[i] - '0';
		int n2 = str2[i] - '0';

		int sum = n1 + n2 + carry;

		carry = sum / 10;
		result[i] = char(sum % 10 + '0');
	}

	if (carry > 0)
	{
		result.insert(0, string(1, carry + '0')); // carry insert '1'
	}

	return result;
}

이 코드에서의 N 에 따른 Performance 를 가지고 있다. Time Complexity 생각을 해보면 대략 T(N) ~= N 이 나온다. 물론 insert 가 일어날때는 약간의 Constant 가 Multiplied 될수 있다.

Subtraction

string Subtract(string str1, string str2)
{
	if (!str1.size() && !str2.size())
		return "0";

	int N = max(str1.size(), str2.size());
	str1 = string(N - str1.size(), '0') + str1;
	str2 = string(N - str2.size(), '0') + str2;

	string result(N, '0');
	int carry = 0;
	for (int i = N - 1; i >= 0; i--)
	{
		int n1 = str1[i] - '0';
		int n2 = str2[i] - '0';

		int sum = n1 - n2 + carry + 10;
		carry = sum / 10;
		result[i] = char(sum % 10 + '0');
		carry -= 1;
	}

	if (result[0] == '0')
	{
		result.replace(0, 1, "");
	}

	return result;
}

마찬가지로 코드에서의 N 에 따른 Performance 를 가지고 있다. Time Complexity 생각을 해보면 대략 T(N) ~= N 이 나온다.

Multiplication

string Multiply(string str1, string str2)
{
	if (!str1.size() && !str2.size())
		return "0";


	int N = max(str1.size(), str2.size());
	str1 = string(N - str1.size(), '0') + str1;
	str2 = string(N - str2.size(), '0') + str2;

	string result(2 * N, '0');

	for (int i = N - 1; i >= 0; i--)
	{ 
		int carry = 0;
		int n1 = str1[i] - '0';
		int k = N + i;
		for (int j = N - 1; j >= 0; j--)
		{
			int n2 = str2[j] - '0';
			int sum = n1 * n2 + int(result[k] - '0') + carry;
			carry = sum / 10;
			result[k] = char(sum % 10 + '0');
			k -= 1;
			std::cout << n1 << " " << n2 << " " << carry << " " << result << endl;
		}

		result[k] = char(carry + '0');
	}

	int i = 0;
	while (result[i] == '0') i += 1;
	result = result.substr(i, 2 * N - i);

	return result;
}

자 여기에서는 조금 다를수 있다. 기본적으로 Two loops 가 있으니까 (N-1) * (N-1) = N^2 로 표현할수 있는데, ‘0’ 의 index 를 찾는데 과정에서, constant * N^2 로 표현할수 있다. 물론 상수를 이야기를 안할수도 있는데 Major 로 Impact 로 줄수 있는걸 찾는게 여기에서는 Main point 이다.

Karatsuba Algorithm

Resource

*