Python 최대공약수(GCD) 축약형 코드 분석

분석 대상 코드

a,b=map(int,input('두 수 입력: ').split()) while b: print(f"{a} ÷ {b} = {a//b} … {a%b}"); a,b=b,a%b print("GCD =",a)

코드의 목적: 사용자에게 두 정수를 입력받아, 유클리드 호제법을 사용하여 최대공약수(GCD)를 구하는 과정을 한 줄의 `while` 루프로 간결하게 표현하고 결과를 출력합니다.


[1] 상세 개념 5가지

1. 유클리드 호제법 (Euclidean Algorithm)

이 코드의 근간이 되는 수학적 원리입니다. 두 정수 a, b에 대하여 'a와 b의 최대공약수'는 'b와 a를 b로 나눈 나머지(r)의 최대공약수'와 같습니다. (gcd(a, b) = gcd(b, a % b)). 이 과정을 나머지가 0이 될 때까지 반복하면, 그 때의 나누는 수가 바로 최대공약수가 됩니다. 이 코드는 이 원리를 매우 압축적으로 구현한 것입니다.

2. Python의 '참(Truthiness)' 평가와 while b:

이 코드의 while b:while b != 0:과 완전히 동일하게 동작합니다. Python에서는 숫자 0False(거짓)로, 0이 아닌 모든 숫자(양수, 음수 포함)는 True(참)로 취급합니다. 이를 'Truthiness'라고 합니다. 따라서 while b:는 'b가 0이 아닐 동안 계속 반복하라'는 의미가 되어, 유클리드 호제법의 종료 조건을 매우 간결하게 표현합니다.

3. 세미콜론(;)을 이용한 한 줄 표현

Python에서는 일반적으로 한 줄에 하나의 명령문만 작성하는 것을 권장하지만, 세미콜론(;)을 사용하면 여러 명령문을 한 줄에 이어서 작성할 수 있습니다. 코드의 print(...); a,b=b,a%b 부분은 원래 두 줄에 걸쳐 써야 할 내용을 세미콜론을 이용해 while 루프의 본문을 한 줄로 만든 것입니다. 이는 코드를 매우 짧게 만들지만, 가독성을 해칠 수 있어 자주 사용되지는 않습니다.

4. 튜플(Tuple)을 이용한 다중 할당

a,b=b,a%b는 유클리드 호제법의 핵심 갱신 과정을 임시 변수 없이 한 줄로 처리하는 Python의 강력한 기능입니다. 이 구문은 우변의 ba%b를 먼저 모두 계산한 후, 그 결과를 좌변의 ab에 각각 할당합니다. 이 덕분에 값이 덮어씌워질 걱정 없이 안전하게 변수 값을 교환하고 갱신할 수 있습니다.

5. F-문자열과 정수 나눗셈 연산자 (//, %)

print(f"...")는 Python 3.6 이상에서 사용 가능한 F-문자열(Formatted String Literal) 문법입니다. 문자열 안에서 변수를 {변수명} 형태로 직접 사용하여 값을 출력할 수 있어 매우 편리합니다.

이 두 연산자는 유클리드 호제법의 과정을 시각적으로 보여주는 데 사용됩니다.


[2] OX 퀴즈 5개

문제 1

while b: 문장은 b가 양수일 때만 반복하고, 음수일 때는 반복하지 않는다.

정답: X
상세 풀이: Python의 Truthiness 규칙에 따라, 0이 아닌 모든 숫자는 `True`로 취급됩니다. 따라서 `b`가 양수이든 음수이든 0만 아니면 `while` 루프는 계속 실행됩니다.

문제 2

세미콜론(;)은 Python에서 여러 줄의 코드를 한 줄로 표현하기 위해 공식적으로 권장되는 방법이다.

정답: X
상세 풀이: 세미콜론은 문법적으로 허용되지만, Python의 스타일 가이드(PEP 8)에서는 가독성을 위해 한 줄에 하나의 명령문을 작성하는 것을 권장합니다. 코드를 인위적으로 줄이기 위한 목적 외에는 잘 사용하지 않습니다.

문제 3

코드가 종료되었을 때, 최대공약수는 변수 b에 저장되어 있다.

정답: X
상세 풀이: while b: 루프는 `b`가 0이 되어 `False`로 평가될 때 종료됩니다. 따라서 루프 종료 시점의 `b`는 항상 0입니다. 최대공약수는 그 직전 단계의 `b` 값이었던, 현재의 `a` 값에 저장되어 있습니다.

문제 4

입력으로 7과 14를 주면, 첫 단계에서 순서가 자동으로 바뀌어 14 \div 7 연산이 수행된다.

정답: X
상세 풀이: 만약 a=7, b=14로 시작하면, 첫 단계는 그대로 7 \div 14 = 0 … 7을 출력합니다. 그 다음 a, b = b, a % b가 실행되면서 a는 14, b는 7이 되어 두 번째 단계부터 큰 수를 작은 수로 나누게 됩니다. 즉, 첫 단계에서는 순서가 바뀌지 않습니다.

문제 5

a,b=b,a%b 구문은 내부적으로 임시 변수를 사용하여 값을 안전하게 교체한다.

정답: O
상세 풀이: 사용자가 직접 임시 변수를 선언할 필요는 없지만, Python 인터프리터는 이 구문을 실행할 때 우변의 값들을 먼저 계산하여 임시 공간(튜플)에 저장했다가 좌변의 변수들에 할당하는 방식으로 동작합니다. 따라서 개념적으로 임시 저장 공간을 사용하는 것이 맞습니다.

[3] 5지선다형 문제 5개

문제 1. 두 정수 54와 24를 입력했을 때, `while` 루프 안의 `print`문은 총 몇 번 실행되는가?

정답: 3번
상세 풀이:
  1. (1회) a=54, b=24. (b != 0) → `54 \div 24` 출력. → a=24, b=6
  2. (2회) a=24, b=6. (b != 0) → `24 \div 6` 출력. → a=6, b=0
  3. (3회 실행 직전) a=6, b=0. (b == 0) → 루프 종료.
어, 잠시만요. 다시 계산해 보겠습니다.
  1. (1회) a=54, b=24. (b!=0). print 실행. 다음 b는 54%24=6.
  2. (2회) a=24, b=6. (b!=0). print 실행. 다음 b는 24%6=0.
b가 0이 되면 다음 루프를 실행하지 않으므로, print문은 총 2번 실행됩니다. 제가 처음 계산을 잘못했네요. 정답은 2번입니다.

문제 1 (수정). 두 정수 54와 24를 입력했을 때, `while` 루프 안의 `print`문은 총 몇 번 실행되는가?

정답: 2번
상세 풀이:
  1. 1단계: `a=54, b=24`. b가 0이 아니므로 루프 실행. `54 \div 24 = 2 … 6` 출력. 다음 값은 `a=24, b=6`.
  2. 2단계: `a=24, b=6`. b가 0이 아니므로 루프 실행. `24 \div 6 = 4 … 0` 출력. 다음 값은 `a=6, b=0`.
이제 `b`가 0이 되었으므로 `while b:` 조건이 거짓이 되어 루프가 종료됩니다. 따라서 `print`문은 총 2번 실행됩니다.

문제 2. 다음 중 while b: 와 의미가 다른 코드는?

정답: 3번
상세 풀이: while b > 0:는 `b`가 양수일 때만 반복합니다. 하지만 원래 코드의 while b:는 `b`가 0이 아닌 모든 수(음수 포함)에 대해 반복하므로, 3번만 의미가 다릅니다. 나머지 보기들은 모두 'b가 0이 아닐 동안'이라는 동일한 의미를 가집니다.

문제 3. gcd(91, 65)를 이 코드로 계산할 때, 루프가 종료된 직후의 `a` 값은 얼마인가?

정답: 3번
상세 풀이:
  1. a=91, b=65 → 다음 a=65, b=26 (91%65)
  2. a=65, b=26 → 다음 a=26, b=13 (65%26)
  3. a=26, b=13 → 다음 a=13, b=0 (26%13)
b가 0이 되어 루프가 종료될 때, a의 값은 13입니다. 이 값이 바로 최대공약수입니다.

문제 4. 이 코드를 아래와 같이 두 줄로 변경했을 때, 발생하는 문제점은 무엇인가?

while b: a = b b = a % b
정답: 2번
상세 풀이: 첫 줄 `a = b`가 실행되면, `a`는 `b`와 같은 값을 가지게 됩니다. 따라서 다음 줄 `b = a % b`는 실질적으로 `b = b % b`가 되어, `b`의 값은 항상 0이 됩니다. 그러면 루프는 단 한 번만 실행되고 끝나버려 올바른 최대공약수를 구할 수 없습니다.

문제 5. 만약 사용자가 입력으로 19 0을 주면 어떻게 되는가?

정답: 3번
상세 풀이: 초기 `b`의 값이 0이므로, while b: 조건은 처음부터 `False`가 됩니다. 따라서 `while` 루프는 단 한 번도 실행되지 않습니다. 프로그램은 바로 루프 다음 줄인 print("GCD =", a)를 실행하여, 초기 `a` 값인 19를 출력합니다.