IT/BaekJoon

[백준/C++] 1008번 A/B : '절대오차'가 무슨 소리일까?

Buang 2022. 7. 12. 10:47
반응형

1. 문제

 

두 정수 A와 B를 입력받은 다음, A/B를 출력하는 프로그램을 작성하시오.

실제 정답과 출력값의 절대오차 또는 상대오차가 

이하이면 정답이다.

 

https://www.acmicpc.net/problem/1008

 

1008번: A/B

두 정수 A와 B를 입력받은 다음, A/B를 출력하는 프로그램을 작성하시오.

www.acmicpc.net

 


2. 풀이

 

1008번 문제를 풀기 위해선 float와 double 개념에 대해서 알아야 한다.

 

이 글에선 추가적으로 문제에서 나온 단어인

'절대오차'에 대해서도 다룰 예정이다.

 

먼저 절대오차에 대해서 알아보자.


 

2-1. 절대오차

1) 절대오차 정의

 

절대오차란 단어가 생소할 수 있다.

일단 사전적 의미를 살펴보자면

 

- 절대오차는 오차의 절대값을 말한다.

- 측정값(M)에서 참값(T)을 뺀 것을 절대오차라 한다.

 

정의를 봐도 무슨 소리인지 모르겠다.

그러니 아래 예시를 봐보자.

 

 

내가 A라는 복잡한 수학문제를 풀고 있다고 해보자.

 

이 수학 문제의 정확한 값(참값or정답)은 22.5인데

이 문제의 답을 구하려면 시간이 너무 오래걸려서

나는 정확한 정답이 도출되기 전에

이 A문제의 답은 23이지 않을까~하고 측정값을 냈다.

그리고 나중에 가서 A문제의 답은 22.5라는 걸 알아냈다.

 

23(측정값) - 22.5(참값) = 0.5 (오차값)

 

여기서 오차는 0.5가 된다.

이 0.5에 절대값을 씌어준다. 즉 만약 오차값이 -.0.5였다면

절대값을 씌어줘서 0.5로 바꿔주는 것이다.

여기선 0.5가 양수기 때문에 절대값을 씌울 필요없이

0.5가 바로 오차, 즉 절대오차가 된다.

 

한 마디로 정의하자면 내가 이 문제의 답이 30일 거야!

라고 예상값을 내봤는데 실제로 봐보니 10이였다면 오차값은

30 -10 = 20이 된다.

 

나는 정확한 예시를 든 게 아니라

절대오차의 느낌이 이렇다, 라고 표현한 것일 뿐이다.

 

사이언스올이란 사이트에서

절대오차 개념에 대해 정확히 설명한 글이 있으니 참고하면 좋을 거 같다.

 

 

2) 절대오차 문제 부분 해석

 

자 이제 문제에서 출력값의 절대오차가

이하 이어야 한다고 했다.

즉 10의 -9승이란 말인데 

 

10의 -1승은 십분의 일, 즉 0.1이다.

10의 -9승은 십억분의 일, 즉 0.000000001이다.

 

십업분의 일은 소수점 자리가 9개다.

'십업분의 일 이하' 라는 말이 문제의 조건으로 있었다.

십업분의 일 이하란 말은 즉

printf로 출력할 때 소수점 자리 수가 9개 이상이 출력 되도록 만들어야 한다는 소리다.

 

숫자가 커서 바로 이해가 안갈 수도 있다.

바로 이해가 갔다면 다음 챕터로 넘어가도 상관없으나

아직 이해가 가지 않는다면 아래 글을 읽어보는 걸 추천드리고 싶다.

 

숫자가 커서 이해가 안 갈 땐 숫자를 줄이면 된다.

10의 -9승 대신, 10의 -2승으로 생각해보자.

 

문제에서 오차범위가 10의 -2승, 즉 100분의 1 이하여야 한다고 했을 때

이 말은 소수점 자리 수가 2 이상이 되도록 만들라는 소리가 된다.

 

0.01은 물론 0.001도 100분의 1이하일 것이고, 0.0000001도 100분의 1이하일 것이다.

즉 소수점 자리 수가 2이상이면 100분의 1 이하가 된다.

 

평소 생각했던 거에서 거꾸로 생각하자.

우리가 보통 숫자 자리 수가 크면 이상이라고 생각해서

혼란이 올 수도 있다. 소수에선 숫자 자리 수가 크면 숫자가 커지는 게 아니라 작아진다.

피자도 나누면 나눌 수록 내가 먹을 수 있는 크기가 줄어드는 것처럼.

 


2) float와 double

 

 

 

float와 double은 실수형 변수를 생성할 때 쓰인다.

두 자료형의 차이점은 누가 더 많은 비트, 소수점을 표현할 수 있느냐이다.

 

가령 1 나누기 3을 했다고 해보자.

 

결과값으론 0.33333333333333333333333 (끝이없다) 무한소수가 나올 것이다.

이걸 컴퓨터 상에선 표현하기 어려우니 어느정도 오차를 감수하고서라도

0.33333333333333333333333(끝이없다)과 가장 근사한 형태 즉, 근사값 형태로 표현할 수 있을 것이다.

 

 

1 나누기 3의 근사값이 0.3 이라고 하는 아이가 있고,

0.33333 이라고 하는 아이가 있다고 해보자.

 

둘 중에 오차가 큰 근사값(정답가 먼 숫자)은 0.3일 것이다. 

오차가 큰 것 보단 아무래도 정답과 가장 가까운, 오차가 작은 근사값이 나오도록 하는 게 좋다.

즉 이 오차를 줄이기 위해 최대한 많은 수(비트)를 담을 수 있는 아이를 사용해야 한다는 건데

 

float는 상대오차가 10의 -7승이다.

즉 7자리까지 비트(or 소수점)를 담을 수 있다.

 

double은 상대오차가 10의 -15승이다.

즉 double형은 15자리까지 비트를 담을 수 있다.

요약하자면 담을 수 있는 비트 수가 float보단 double이 더 많다.

 

문제에선 절대오차/상대오차가 10의 -9승 이하여야 한다고 했다.

즉 소수점 9자리 이상이 표현되도록 하라는 것이며

float를 사용하면 소수점 9자리 이상을 표현하지 못한다.

 

그래서 여기선 float가 아닌 double을 사용해야 한다.

 


3. 코드

 

#include <stdio.h>
 
int main(void) {

    double A;
    double B;
    
    scanf("%lf", &A);     // %lf는 double을 입력할 때 쓰인다.
    scanf("%lf", &B);     // %d는 정수(int)를 입력할 때 쓰는 것과 맥락이 비슷하다.
    
    printf("%.9lf", A/B); // 문제를 보면 소수점 9자리 이상 출력되도록 해야 했었다.
                          // 나는 딱 9자리만 나올 수 있도록 하기 위해서 .9를 작성했다.

    return 0;
}

 

만약 int A; 를 입력했다면 scanf부분에서

scanf("%d", &A);라고 썼을 것이다.

 

int(정수)를 입력할 때 쓰이는 게 %d다.

float를 사용했다면 %f를

double을 사용했다면 %lf 를 써준다.

 

마지막에 printf로

출력될 때 소수점 몇 자리까지 출력해야 할지 지정해준다.

 

형식은

 

"%.(출력될 소수점 자리 수)lf"형태다.

 

만약 소수점 자리 수가 10자리로 출력됐음 한다면

 

%.10lf로 바꿔주면 된다.

 

 

아래는 간결한 코드 버전이다.

 

#include <stdio.h>
 
int main(void) {

    double A, B;
    
    scanf("%lf %lf", &A, &B);
    
    printf("%.9lf", A/B);

    return 0;
}
반응형