백준 15858번 - Simple Arithmetic / C++

김종민·2025년 6월 5일

문제풀이

목록 보기
5/5
post-thumbnail

1. 문제

문제 링크


2. 풀이

long double 자료형으로만 풀면 예제 3번처럼 높은 자릿수의 연산에서 오차가 생겨 100점을 받지 못한다.
ex)

int main() {
	long double a, b, c;
	cin >> a >> b >> c;
	cout << setprecision(18) << fixed << a * b / c << endl;
}

결과

123456789 987654321 1 // input
121932631112635264.000000000000000000 // output (오답)

정답

121932631112635269.000000000000000000 // 5의 오차 발생

long long inta * b만 계산해보면
121932631112635269로 맞게 계산되지만 같은 숫자를
long double로 형변환하는 순간 오차가 생기는 것을 확인할 수 있었다.

📌 자료형 참고

타입자료형자릿수 정확도안전 범위 (정수)특이점
long double부동소수점약 19자리 유효숫자지수부는 넓지만 정수형 정확도는 제한적19자리 넘어가면 근사치 (오차) 발생
long long int정수64비트 정수±9 x 10^18정수 연산에서 정확 (단, 오버플로우 주의)

문제 조건상 long long int로 정수부 커버 가능하므로 정수부 + 소수부로 나누어 연산 후 결과를 출력하면 된다.

출력할 때 string으로만 더해야지 합연산하면 계산 범위 넘어서 다시 오차 생김

정수부

long long int a , b , c , ab;
ab = a * b;
cout << ab/c;

결과

123456789 987654321 7 // input (예제 4)
17418947301805038 // output (정수부)

ab/c를 통해 정수 부분의 수를 오차없이 얻어낼 수 있음


소수부

long long int res = ab % c;
cout << (long double) res/c << endl;
cout << setprecision(18) << fixed << (long double)res / c << endl;

나머지를 다시 c로 나누어서 소수부 계산을 한다.

결과

123456789 987654321 7 // input
0.428571			  // output (소수부)
0.428571428571428548  // 자릿수 설정

출력

정수부와 소수부 모두 구했으면 알맞게 출력해야하는 일이 남았다.
정수부를 출력하고 소수부에서 구한 수 0.xxx에서 0을 떼고 출력해야 우리가 원하는 정수.소수가 나올 것이다.
입출력 조작자만으로는 우리가 원하는 형태의 출력을 만들 수 없기때문에 문자열을 파싱해서 정수부와 소수부를 결합할 수 있다.

📌 하지만 문제 풀이를 찾아보면 간단한 자릿수 조작으로 이를 해결했다.

정수부의 수를 구할 때 c * 10으로 나누어 1의 자릿수 정수를 남겨두고
소수부의 수를 구할 때 그 나머지로 값을 구하는 식.

예제 4번으로 다시 예를 들어보자면

long long int a , b , c , ab;
ab = a * b;
cout << ab/(10*c) << endl;			// 10 * c로 나누기
long long int res = ab % (10*c);	// 10 * c로 나눈 나머지
cout << setprecision(18) << fixed << (long double)res / c << endl;

출력

123456789 987654321 7	// input
1741894730180503		// output (정수부 - 10의 자리부터)
8.428571428571428825	// output (소수부 - 1의 자리부터)

줄바꿈 없이 한 줄에 출력하면 17418947301805038.428571428571428825로 우리가 원하는 답이 나온다.


📌 조건 추가

10의 자리 정수부를 미리 출력하게되는데
ab10*c보다 작은 경우가 있다면 필요없는 0이 먼저 출력되기 때문에 if(ab>=(10*c)) 조건을 추가한다.

조건이 빠진 경우

5 3 2				  // 5*3 < 2*10
07.500000000000000000 // 쓸모없는 숫자 0이 먼저 출력됨

📌 출력 형식

문제에서 요구하는 오차 인정 범위는 소수점 6자리이고
cout 디폴트 자릿수는 6이다.
하지만 fixedfalse라면 정수, 소수 구분 없이 6자리로 출력하므로 출력 형식을 지정하지 않으면 오답처리가 된다.

따라서 안전하게 예제에 나온 자릿수인 18자리로 설정하거나
cout << setprecision(18) << fixed

cout << fixed만 해줘도 괜찮다. (디폴트가 6자리이므로)


3. 코드

#include <bits/stdc++.h>
using namespace std;

int main() {
	long long int a, b, c , ab;
	cin >> a >> b >> c;
    ab = a*b;
    if(ab >= 10*c)
    {
        cout << ab/(10*c);
        ab %= 10*c; // res대신 ab를 덮어씀
    }
	cout << setprecision(18) << fixed << (long double)ab / c << endl;
}
profile
정리와 기록

0개의 댓글