Charlloss Dev

Charlloss'Dev Technology & TIL(Today I Learn) Blog

Euclidean algorithm

Euclidean algorithm

유클리드 호제법은 2개의 자연수 또는 정식의 최대공약수를 구하는 알고리즘의 하나이다.

호제법이란 말은 두 수가 서로 상대방 수를 나누어서 결국 원하는 수를 얻는 알고리즘을 나타낸다.

2개의 자연수(또는 정식) a, b에 대해서 a를 b로 나눈 나머지를 r이라 하면(단, a>b), a와 b의 최대공약수는 b와 r의 최대공약수와 같다. 이 성질에 따라, b를 r로 나눈 나머지 r’를 구하고, 다시 r을 r’로 나눈 나머지를 구하는 과정을 반복하여 나머지가 0이 되었을 때 나누는 수가 a와 b의 최대공약수이다. 이는 명시적으로 기술된 가장 오래된 알고리즘으로서도 알려져 있으며, 기원전 300년경에 쓰인 유클리드의 《원론》 제7권, 명제 1부터 3까지에 해당한다.

최대 공약수

예시

1071과 1029의 최대공약수를 구하면,

  • 1071은 1029로 나누어떨어지지 않기 때문에, 1071을 1029로 나눈 나머지를 구한다. => 42
  • 1029는 42로 나누어떨어지지 않기 때문에, 1029를 42로 나눈 나머지를 구한다. => 21
  • 42는 21로 나누어떨어진다. 따라서, 최대공약수는 21이다.

78696과 19332의 최대공약수를 구하면

78696 = 19332×4 + 1368
19332 = 1368×14 + 180
 1368 = 180×7 + 108
  180 = 108×1 + 72
  108 = 72×1 + 36
   72 = 36×2 // MOD = 0

따라서, 최대공약수는 36이다

코드

재귀 호출로 해결 가능

아래 코드는 b가 0이 될때까지 계속해서 재귀 호출을 해주고, 0이 되면 a를 반환한다.

int gcd(int a, int b)
{
    /*
     * eqaul logic
     * if (b==0) return a;
     * gcd(b, a%b)
    */
	return b ? gcd(b, a%b) : a;
}

재귀 호출이 문제가 된다면

int gcd(int a, int b)
{
    while (b > 0)
    {
        int tmp = a;
        a = b;
        b = tmp%b;
    }
    return a;
}

최소공배수

최소공배수는 최대공약수와는 반대로, 두 정수가 공통적으로 가지는 배수 중 가장 작은 값을 의미합니다. 최소공배수는 최대공약수와 밀접한 관계가 있는데, 정수 a, b의 최대공약수 G = gcd(a, b)에 대하여 아래의 식을 만족하는 정수 x와 y가 존재합니다. $a = Gx$, $b = Gy$ (단, x, y는 정수) 이 때 a * b = GGx*y 임을 알 수 있고, G는 두 수의 최대 공약수이며 x와 y는 서로소인 관계를 가집니다. 집합적으로 생각하면, a와 b의 합집합은 G, x, y이고 이 세 수를 곱한 Gxy가 최소공배수가 됨을 알 수 있습니다.

  1. a * b = GGx*y
  2. a * b / G = GGx*y / G (양변에 최소 공약수를 나누어 줌)
  3. a * b / G = Gxy(최소공배수)
  4. 최소공배수 = a * b / G

그러므로 두 수의 최소공배수 L = lcm(a, b)은 L= lcm(a, b)= a * b / gcd(a, b)이 성립합니다.

최대공약수와 최소공약수 사이의 관계와 유클리드 호제법을 활용해 구할 수도 있습니다

int lcm(int a, int b)
{
	return a * b / gcd(a,b);
}