문제 개요
사용자로부터 실행 시점에 두 개의 정수(분자와 분모)를 입력받아, 동적 메모리 할당(dynamic memory allocation)을 활용해 나눗셈 결과인 소수를 계산하고, 이를 문자열 형식으로 반환하는 프로그램을 작성하는 것이 목표입니다.
특히 나눗셈 결과가 무한소수일 경우, 반복되는 소수 부분을 괄호 ()로 묶어 표시하는 것이 핵심 포인트입니다.
해결 방법
이 문제는 다음과 같은 단계로 해결할 수 있습니다.
- 입력된 분자와 분모의 부호를 확인하여 결과가 음수인지 판별합니다.
- 정수 부분과 소수 부분을 분리합니다.
- 소수점 이하 자릿수를 계산하면서 이미 등장했던 나머지 값이 다시 나타나는지 추적합니다.
- 나머지가 반복되면 해당 지점부터 괄호로 묶어 순환소수임을 표시합니다.
- 필요에 따라
malloc과realloc으로 메모리를 동적으로 확장합니다.
입력 예시
Numerator1 = 3 Denominator1 = 2 Numerator2 = 4 Denominator2 = 7
출력 예시
Fractional part1: 1.5 Fractional part2: 0.(571428)
위 예시에서 4 ÷ 7 = 0.571428571428... 로 무한히 반복되는 순환소수이므로, 반복 구간인 571428이 괄호로 묶여 0.(571428) 형태로 출력됩니다.
C 언어 구현 코드
다음은 분자와 분모를 받아 소수를 문자열 형식으로 변환하는 전체 C 프로그램입니다.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
char* fractionToDecimal(int numerator, int denominator) {
char *p;
int psz, n, *dec, dsz, x;
long long num, den, k, f;
int i, repeat_at;
int neg = 0;
psz = dsz = 100; n = x = 0;
p = malloc(psz * sizeof(char));
// 부호 판별: 분자와 분모의 부호가 다르면 음수
neg = ((numerator > 0 && denominator < 0) ||
(numerator < 0 && denominator > 0)) ? 1 : 0;
num = numerator;
den = denominator;
num = (num < 0) ? -num : num;
den = (den < 0) ? -den : den;
// 정수 부분과 나머지 계산
k = num / den;
f = num % den;
if (neg && (k || f)) p[n ++] = '-';
n += sprintf(&p[n], "%lld", k);
// 나머지가 0이면 정수만 반환
if (!f) {
p[n] = 0;
return p;
}
p[n ++] = '.';
dec = malloc(dsz * sizeof(int));
repeat_at = -1;
if (f < 0) f = -f;
// 소수 부분 계산 및 순환 여부 검사
while (f) {
for (i = 0; i < x; i += 2) {
if (dec[i] == f) {
repeat_at = i;
goto done;
}
}
if (x + 1 >= dsz) {
dsz *= 2;
dec = realloc(dec, dsz * sizeof(int));
}
dec[x ++] = f;
f *= 10;
k = f / den;
dec[x ++] = k;
f = f % den;
}
done:
// 결과 문자열 조립
for (i = 0; i < x; i += 2) {
if (n + 3 > psz) {
psz *= 2;
p = realloc(p, psz * sizeof(char));
}
if (repeat_at == i) {
p[n ++] = '(';
}
p[n ++] = '0' + dec[i + 1];
}
if (repeat_at != -1) p[n ++] = ')';
p[n ++] = 0;
free(dec);
return p;
}
int main(void){
int n, d;
printf("enter numerator1 and denominator1:");
scanf("%d%d", &n, &d);
printf("n = %d, d = %d ", n, d);
printf("\nFractional part1: %s \n", fractionToDecimal(n, d));
printf("enter numerator2 and denominator2:");
scanf("%d%d", &n, &d);
printf("\nn = %d, d = %d ", n, d);
printf("\nFractional part2: %s\n ", fractionToDecimal(n, d));
return 0;
}코드 핵심 로직 설명
1. 부호 처리
분자와 분모 중 하나만 음수라면 결과도 음수가 됩니다. 코드에서는 두 값의 절댓값을 취한 뒤 계산하고, 필요한 경우 앞에 음수 기호(-)를 붙입니다.
2. 순환소수 감지
나눗셈 과정에서 나오는 나머지(rest) 값을 배열에 저장해 두었다가, 같은 나머지가 다시 등장하면 그 지점부터 소수 자릿수가 반복된다는 의미입니다. 이때 repeat_at 변수에 반복 시작 위치를 기록하여 출력 시 괄호로 처리합니다.
3. 동적 메모리 관리
결과 문자열과 나머지 저장 배열은 처음에 100 크기로 할당되며, 공간이 부족해지면 realloc을 통해 크기를 두 배씩 늘려가며 안전하게 확장합니다.
실행 결과
위 프로그램을 실행하면 다음과 같은 결과를 확인할 수 있습니다.
enter numerator1 and denominator1:4 5 n = 4, d = 5 Fractional part1: 0.8 enter numerator2 and denominator2:5 9 n = 5, d = 9 Fractional part2: 0.(5)
첫 번째 입력 4 ÷ 5는 나누어떨어지는 유한소수 0.8이 출력되고, 두 번째 입력 5 ÷ 9는 0.5555...로 무한히 반복되므로 순환 부분을 괄호로 묶은 0.(5)가 출력됩니다.
마무리
이 프로그램은 단순한 나눗셈을 넘어, 순환소수 판별 알고리즘과 동적 메모리 할당 기법을 함께 학습할 수 있는 좋은 예제입니다. 특히 LeetCode의 "Fraction to Recurring Decimal" 문제와 유사한 방식으로, 코딩 테스트 준비에도 도움이 됩니다.