프로그래머스 120817 - 배열의 평균값 (Lv.0)
핵심 접근 — 합은 int로 정확히, 나눌 때만 double 캐스팅
프로그래머스 120817 - 배열의 평균값 (Lv.0)
출처: https://school.programmers.co.kr/learn/courses/30/lessons/120817
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// 프로그래머스 120817 - 배열의 평균값 (Lv.0)
// https://school.programmers.co.kr/learn/courses/30/lessons/120817
// 문제 설명
// 정수 배열 numbers가 매개변수로 주어진다. numbers 원소의 평균값을 반환하라.
// 제약 조건
// 0 <= numbers의 원소 <= 1,000
// 1 <= numbers의 길이 <= 100
// 정답의 소수 부분이 .0 또는 .5인 경우만 입력으로 주어진다.
// Example
// Input : [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
// Output: 5.5 (합 55 / 개수 10)
//
// Input : [89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]
// Output: 94.0 (합 1034 / 개수 11)
// 접근 — 정수로 모으고, 나누는 순간에만 실수로
// 함정은 알고리즘이 아니라 자료형 두 군데다.
// 1) 합계: accumulate의 초기값을 0(int)으로 주면 누적도 int로 진행된다. 원소를 double로
// 바꿔가며 더하면 부동소수 오차가 쌓이지만, 정수로 모으면 합은 항상 정확하다.
// 상한이 100 x 1000 = 100,000이라 int로 충분.
// 2) 나눗셈: vector::size()의 반환형은 size_t(부호 없는 정수)다. sum / numbers.size()로
// 쓰면 int인 sum이 size_t로 승격돼 "정수 나눗셈"이 되고 5.5가 5로 잘린다.
// 한쪽만 double로 캐스팅하면 나머지 한쪽도 double로 승격돼 실수 나눗셈이 된다.
// 시간 O(n), 공간 O(1)
#include <string>
#include <vector>
#include <numeric>
using namespace std;
double solution(vector<int> numbers) {
int sum = accumulate(numbers.begin(), numbers.end(), 0); // 최대 100 * 1000 = 100,000 — int로 충분
return static_cast<double>(sum) / numbers.size(); // size()가 size_t라 캐스팅 없으면 정수 나눗셈
}
정리
accumulate의 초기값이 누적 자료형을 결정한다.0을 주면 int로,0.0을 주면 double로,0LL을 주면 long long으로 누적된다. 원소가 정수인데 결과만 실수인 문제는 정수로 모아 마지막에 한 번만 나누는 것이 정확도·성능 양쪽에서 유리하다. 실수로 누적하면 덧셈마다 반올림 오차가 생긴다.size()는size_t(부호 없는 64비트) 라서sum / numbers.size()는 int를 unsigned로 끌어올린 뒤 정수 나눗셈을 한다. 5.5가 5로 잘리고, 반환형이 double이어도 이미 잘린 값이 승격될 뿐이다.static_cast<double>한쪽만 붙이면 다른 피연산자도 double로 승격돼 해결된다.- 상한 점검: 원소 1,000 × 길이 100 = 100,000. int(약 21억) 대비 한참 아래라
long long이 필요 없다. 반대로 원소가 10^9급이었다면 int 합이 넘쳤을 것이고, 그때는accumulate(..., 0LL)이 답이다. - “소수 부분이 .0 또는 .5”라는 제약의 의미 — 0.5는 2의 거듭제곱 분수라 이진 부동소수로 오차 없이 표현된다. 그래서 이 문제에 한해
== 5.5같은 등호 비교가 안전하다. 일반적인 평균(1/3 등)은 이진수로 딱 떨어지지 않으므로 등호 대신fabs(a - b) < eps를 써야 한다. - 같은 계열로 묶어 두면 좋은 것은 “정수로 계산하다 마지막에만 실수로 바꾸는” 문제군이다. 평균·비율·할인율처럼 나눗셈이 한 번 끼는 문제는 전부 이 축에서 갈린다 — 나누는 시점을 뒤로 미룰수록 누적 오차가 줄고, 아예 나누지 않고 양변에 분모를 곱해 정수 비교로 바꾸면 오차가 사라진다.
- 검증: 예제 2개(5.5, 94.0)와 경계 케이스(길이 1의
[0]→ 0.0, 길이 100 전부 1000 → 1000.0) 통과 (MSVC/std:c++17 /utf-8컴파일·실행).
핵심 요약 — 정수 배열의 평균은 합을 int로 정확히 모으고 나누는 순간에만 double로 캐스팅한다.
size()가size_t라 캐스팅을 빠뜨리면 정수 나눗셈으로 소수부가 통째로 잘린다.
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.