반응형
💻 Problem
유리수 분수를 소수로 나타내면, 소수점 아래 자리가 유한 개인 경우(1/8 = 0.125)와 어떤 자리에서부터 일정한 숫자가 한없이 되풀이되는 경우(1/11 = 0.090909...)가 있다.
소수를 입력받은 뒤, 분수로 나타내는 프로그램을 작성하시오.
예제 입력 1
3
0.5
0.(3)
0.6(142857)
예제 출력 1
1/2
1/3
43/70
💡 Approach
순환소수를 분수로 나타내는 문제이다.
순환소수를 분수로 변환하는 법을 노트에 정리해 봤다.
이를 바탕으로 구현하면 된다.
입력을 슬라이싱해서 소수 뒷부분만 살펴보도록 했다.
주어진 소수가 유한소수일 경우, 분자는 소수 뒷부분 그대로이고 분모는 10^(소수 뒷부분 길이)가 된다.
주어진 소수가 무한소수(순환소수)일 경우, 소수 뒷부분을 비반복 구간과 반복 구간으로 나눈다.
- k: 비반복 구간 (길이: m)
- r: 반복 구간 (길이: n)
분자는 int(k + r) - int(k or '0')이 되고,
- 숫자로 생각하면 실제 값은 (k * (10 ** n) + r) - k이지만
- k와 r이 문자열이므로 그냥 두 문자열을 합치면 된다.
분모는 (10 ** (m + n)) - (10 ** m)이 된다.
분자와 분모를 구했으면 둘의 최대공약수를 구한다.
그러고 나서 각 분자와 분모를 최대공약수로 나눠주면 된다.
✏️ Solution
import sys
from math import gcd
input = sys.stdin.readline
for _ in range(int(input())):
s = input().rstrip()[2:]
if '(' not in s:
numerator = int(s) # 분자
denominator = 10 ** len(s) # 분모
else:
i = s.index('(')
k = s[:i] # 비반복 구간
r = s[i + 1:-1] # 반복 구간
m = len(k) # 비반복 구간 길이
n = len(r) # 반복 구간 길이
numerator = int(k + r) - int(k or '0')
denominator = (10 ** (m + n)) - (10 ** m)
g = gcd(numerator, denominator) # 최대공약수
print(f'{numerator // g}/{denominator // g}')
반응형