[6986번] 절사평균
Algorithm/백준 문제 풀이

[6986번] 절사평균

반응형

백준 6986번: 절사평균

 

6986번: 절사평균

첫째 줄에 절사평균(N, K)를, 둘째 줄에 보정평균(N, K)를 각각 소수점이하 셋째 자리에서 반올림하여 둘째 자리까지 출력한다. 예를 들어 결과값이 9.667인 경우 9.67로, 5인 경우 5.00으로, 5.5인 경우에는 5.50으로 출력한다.

www.acmicpc.net

절사평균, 보정평균에 대해 다룬 문제입니다.

이 문제는 사실 구현 및 수학 문제이니 구현 자체는 쉽습니다.

그런데 왜 이 문제에 대해 포스팅 하려 할까요?

 

일단 코드 보시고 알려드리도록 하죠.


 입력

첫째 줄에 전체 점수의 개수 N과 제외되는 점수의 개수 K가 빈칸을 사이에 두고 주어진다.

N은 3 이상 100,000 이하의 자연수이다. K는 0 이상 (N/2)-1 이하로 주어진다.

그 다음 N줄에는 각 심판의 점수가 한 줄에 하나씩 주어진다.

점수는 0 이상 10 이하의 실수로 소수점이하 첫째 자리까지 주어진다.

 출력

첫째 줄에 절사평균(N, K)를, 둘째 줄에 보정평균(N, K)를 각각 소수점이하 셋째 자리에서 반올림하여 둘째 자리까지 출력한다.

예를 들어 결과값이 9.667인 경우 9.67로, 5인 경우 5.00으로, 5.5인 경우에는 5.50으로 출력한다.


사용 언어: C++

#include <cstdio>
#include <algorithm>
// 부동소수점의 한계를 인해 발생하는 문제를 없애주기 위함!
#define ERROR 0.00000001

int N, K;
double sc[100002];

double jul() {
    double sum = 0;
    for(int i = K; i < N - K; ++i) sum += sc[i];
    return sum / (N - K * 2);
}

double bo() {
    double sum = 0;
    sum += sc[K] * K;
    for(int i = K; i < N - K; ++i) sum += sc[i];
    sum += sc[N - K - 1] * K;
    return sum / N;
}

int main() {
    scanf("%d%d", &N, &K);
    for(int i = 0; i < N; ++i) scanf("%lf", sc + i);
    std::sort(sc, sc + N);
    
    printf("%.2lf\n", jul() + ERROR);
    printf("%.2lf", bo() + ERROR);
}

보시면 알겠지만 단순히 답만을 낸 것이 아니라 ERROR라는 상수를 통해 값을 조금 바꿔주고 있습니다.

 

〃그 이유가 뭘까요?

 

바로 C++(혹은 C) 내에서의 부동소수점 연산 때문입니다.

컴퓨터는 정확한 소수를 나타내지 못한다는 사실은 다 아실 겁니다.

그래서 최대한 정확한 비교를 하려 하지만 그럼에도 한계점이 생기기 마련입니다.

 

double a = 1.0

if( a ==  1.0 ) 
   printf("not error");
else
   printf("error");

이 코드는 가끔 error를 출력합니다. 이유는 

a = 0.9999999······· 혹은 a = 1.000000000000000001 일 때를 다르게 보기 때문입니다.

 

그래서 컴퓨터는 항상 특정 오차값을 이용해 비교하고자 하는 값과 오차값의 차이가 오차 범위보다 작을 시 참으로 판단하게 됩니다.

double a = 1.0

if( fabs( a - 1.0 )  <= ERROR  ) 
   printf("not error");
else
   printf("error");

예를 들어 이렇게 말입니다.

그 오차 범위를 확 좁혀주기 위해, 우리는 ERROR라는 충분히 작은 소수를 더해 그 범위 내로 들어가게 해줌으로써 해당 문제를 해결할 수 있게 됩니다.

참고 : Nada님의 답변

저도 처음에는 당연히 맞다고 생각하고 제출을 했지만 틀렸습니다.

그리고 위의 답변을 참고해 겨우 알게 되었습니다.

 

앞으로 소수점의 비교연산시에는 항상 조심하도록 해야겠다고 생각했습니다.

반응형