07. 일곱 번째 수업: 끝없이 반복되는 무한루프, 순환소수 (Repeating Decimals)

앞서 분모의 소인수가 2와 5뿐이라면 딱 떨어지는 ‘유한소수’가 된다고 배웠습니다. 그렇다면 2나 5가 아닌 불순물(3, 7, 11 등)이 조금이라도 섞여 있는 무시무시한 분수라면 어떻게 될까요? 컴퓨터 계산기를 두드려보면 소수점 밑으로 숫자 끝없이 밀려 나오는 것을 볼 수 있습니다.


1. 1을 3으로 나누면 일어나는 일

가장 대표적인 예가 $\frac{1}{3}$ 입니다. 계산기에 $1 \div 3$을 입력해 보면 모니터 화면 끝까지 0.33333333...이 출력됩니다. 왜 이런 일이 발생할까요? 나눗셈의 세로줄 계산(Long Division)을 상상해 보세요.

  1. $10$을 $3$으로 나눕니다. 몫은 $3$, 나머지는 $1$입니다.
  2. 뒤에 $0$을 하나 더 붙여서 다시 $10$을 $3$으로 나눕니다. 몫은 $3$, 나머지는 또 $1$입니다.
  3. 또 $0$을 붙이고 나눕니다… 무한 반복!

이처럼 나눗셈 도중 동일한 ‘나머지’ 패턴에 다시 진입하면, 그 이후부터 몫은 무한루프(Infinite Loop)에 빠진 것처럼 영원히 같은 숫자 배열을 찍어내게 됩니다. 수학에서는 이렇게 소수점 아래에서 특정한 숫자 배열이 끝없이 반복되는 소수를 순환소수(Repeating Decimal)라고 부릅니다.

2. 순환마디 (다이어트 된 무한의 표현)

$0.3333…$이나 $0.818181…$처럼 무한히 써야 하는 숫자를 공책에 일일이 다 적을 순 없겠죠? 수학자들은 몹시 게으르고 효율적인 것을 좋아하기 때문에, 반복되는 가장 짧은 패턴을 찾아내어 순환마디라는 이름을 붙이고 그 숫자 위에 작은 ‘점’을 찍어 깔끔하게 압축해버렸습니다.

  • $0.3333\dots = 0.\dot{3}$ (순환마디: 3)
  • $0.818181\dots = 0.\dot{8}\dot{1}$ (순환마디: 81)
  • $0.23454545\dots = 0.23\dot{4}\dot{5}$ (순환마디: 45)

3. 이집트의 지혜: 모든 순환소수는 다시 분수로!

신비롭게도, 이런 무한히 끝을 알 수 없는 무한소수들조차 규칙성(패턴)만 있다면 모조리 “유리수(분수)”로 다시 되돌릴 수 있습니다. 무한을 뚫고 뼈대($a/b$ 비율)로 돌아올 수 있다는 것이 유리수의 막강한 힘입니다.

공식: 소수점 아래 전체 숫자를 적고, 순환하지 않는 숫자를 통째로 빼서 ‘분자’를 만듭니다. ‘분모’는 순환마디의 개수만큼 $9$를 쓰고, 그 뒤에 순환하지 않는 소수점 아래 자리 수만큼 $0$을 붙입니다.

  • $0.\dot{8}\dot{1} = \frac{81 - 0}{99} = \frac{81}{99} = \frac{9}{11}$
  • $0.23\dot{4}\dot{5} = \frac{2345 - 23}{9900} = \frac{2322}{9900}$
나눗셈의 나머지 과정에서 동일한 숫자가 다시 발생하며 무한 루프에 진입하는 컴퓨터 로직(While Loop)과 연결된 SVG 인포그래픽

4. 파이썬과 무한루프 디버깅

우리가 소프트웨어를 만들 때 가장 조심해야 할 버그 중 하나가 바로 이 ‘나머지의 무한 반복’ 원리에서 비롯되는 While(True) 무한루프입니다. 한 번 코드 패턴이 반복에 갇히면 CPU는 영원히 $3, 3, 3…$을 찍어내다가 멈춰버리게 됩니다.

# [Python] 나눗셈 무한루프 시뮬레이터 (순환마디 찾기)
numerator = 1
denominator = 7  # 1 / 7 = 0.142857 142857 ... (순환마디 6개)

print(f"{numerator} ÷ {denominator} 계산 추적기 시작!")

remainder_history = []
decimal_digits = []

rem = numerator % denominator

# 모의 나눗셈 루프 시작
while rem != 0 and rem not in remainder_history:
    remainder_history.append(rem)
    
    # 0을 뒤에 하나 붙여서 나눈다 (소수점 뒤로 자리 이동)
    rem *= 10
    quotient = rem // denominator
    rem = rem % denominator
    
    decimal_digits.append(str(quotient))

print("소수점 배열:", "".join(decimal_digits))

if rem == 0:
    print("-> 나머지가 0이 되어 나누어 떨어졌습니다! (유한소수)")
else:
    print(f"-> 앗! 나머지 {rem} 가 역사(History)에 이미 존재합니다.")
    print("-> 동일한 패턴 무한 루프 진입 감지! (순환소수)")

[실행 결과]

1 ÷ 7 계산 추적기 시작!
소수점 배열: 142857
-> 앗! 나머지 1 가 역사(History)에 이미 존재합니다.
-> 동일한 패턴 무한 루프 진입 감지! (순환소수)

파이썬 코드에서 과거에 나왔던 나머지(1)가 다시 출현하는 순간 반복문을 끊어버리는 방어 로직을 짰습니다. 이 프로그램이 잡아낸 $142857$ 이 바로 $\frac{1}{7}$ 의 위대한 ‘순환 마디’입니다!

서브목차