공장의 센서들이 같은 시간 동안 잰 값을 모았다.
센서마다 값의 평균과 표준편차를 구해 값이 얼마나 흔들렸는지 본다.
첫 줄에 센서 수 s가 주어진다.
다음 s줄에 센서마다 값의 개수 n과 정수 값 n개가 빈칸으로 나뉘어 한 줄에 주어진다.
평균 m은 값의 합을 n으로 나눈 실수다.
표준편차는 값마다 (값 - m)을 제곱해 모두 더하고, 그 합을 n으로 나눈 다음 제곱근을 구한 것이다(n - 1이 아니라 n으로 나눈다).
센서마다 한 줄에 평균과 표준편차를 소수 셋째 자리까지 반올림해 빈칸 하나로 띄워 입력 차례대로 출력하라.
정수로 떨어져도 소수 세 자리를 쓴다(80 → 80.000).
반올림이 경계에 걸리지 않도록, 평균이나 표준편차에 1000을 곱한 값의 소수 부분이 0.49 이상 0.51 이하인 입력은 주어지지 않는다.
입력
1 ≤ s ≤ 20, 1 ≤ n ≤ 1,000, 0 ≤ 값 ≤ 1,000,000,000, 평균·표준편차 × 1000의 소수 부분이 0.49~0.51인 입력은 없다
실행하면 이 줄들이 차례로 input()·표준 입력으로 들어가요(실행 중에 묻지 않아요).
$ 준비됐어요
코드를 입력해 풀려면 PC에서 열어 주세요. 모바일에서는 문제와 풀이를 볼 수 있어요.
다른 언어로는?언어별 풀이 보기 · 8개 언어 풀이
나눗셈에서 첫째 함정이 나와요. Python 3의 /, JS·TS의 /, 크레이콘의 /는 언제나 실수 나눗셈이라 sum / n이 그대로 1.667이에요. C·C++·Java·C#에서는 두 정수끼리 나누면 정수 나눗셈이라 5 / 3이 1이 되고, 그 값을 double에 넣어도 1.0이에요. 그래서 (double)sum / n(C++ static_cast<double>(sum) / n)처럼 나누기 전에 한쪽을 실수로 바꿔야 해요. 둘째 함정은 합의 크기예요. 10^9짜리 값 1,000개의 합은 10^12라 C·C++·Java·C#의 int(약 21억)를 넘으니 long long·long에 모아요. Python 정수와 JS·TS·크레이콘의 double은 이 정도면 정확해요. 셋째 함정은 공식이에요. 분산을 "제곱의 평균 - 평균의 제곱"으로 한 번에 구하면, 값이 10^9 가까이이고 흔들림이 작을 때 10^18쯤 되는 두 실수를 빼게 돼요. double은 유효숫자가 약 16자리라서 그 차이(예: 0.5)가 오차 수백에 묻히고, 음수가 나와 제곱근이 NaN이 되기도 해요. 여덟 언어 모두 같은 double이라 똑같이 무너져요. 평균을 먼저 구하고 (값 - 평균)을 제곱해 더하는 두 번 훑기가 안전해요. 제곱근은 Python math.sqrt, JS·TS Math.sqrt, Java Math.sqrt, C# Math.Sqrt, C sqrt(<math.h>, gcc는 -lm), C++ std::sqrt(<cmath>), 크레이콘 수학.제곱근이에요. 소수 세 자리는 Python f"{x:.3f}", JS·TS toFixed(3), Java String.format("%.3f"), C# ToString("F3"), C·C++ printf("%.3f"), 크레이콘 글자.소수자리맞추기(x, 3)예요. Java String.format과 C# ToString은 컴퓨터의 지역 설정에 따라 소수점이 쉼표로 나올 수 있어서 Java는 Locale.ROOT, C#은 CultureInfo.InvariantCulture를 넘겨요.
Pythonmain.py · 9 줄
import maths = int(input())for _ in range(s): n, *xs = map(int, input().split()) mean = sum(xs) / n # Python 3의 /는 늘 실수 나눗셈이다 # 평균을 먼저 구하고 평균과의 차를 제곱해 더한다(두 번 훑기): 큰 수끼리 빼는 일이 없다 var = sum((x - mean) ** 2 for x in xs) / n print(f"{mean:.3f} {math.sqrt(var):.3f}")
JavaScriptmain.js · 12 줄
const lines = require("fs").readFileSync(0, "utf8").split("\n");const s = Number(lines[0]);const out = [];for (let i = 1; i <= s; i++) { const [n, ...xs] = lines[i].trim().split(/\s+/).map(Number); // JS의 수는 모두 double이라 /는 늘 실수 나눗셈이다(합 10^12도 2^53 안이라 정확하다) const mean = xs.reduce((a, b) => a + b, 0) / n; // 평균을 먼저 구하고 평균과의 차를 제곱해 더한다(두 번 훑기): 큰 수끼리 빼는 일이 없다 const variance = xs.reduce((acc, x) => acc + (x - mean) ** 2, 0) / n; out.push(`${mean.toFixed(3)} ${Math.sqrt(variance).toFixed(3)}`);}console.log(out.join("\n"));
TypeScriptmain.ts · 13 줄
import { readFileSync } from "node:fs";const lines: string[] = readFileSync(0, "utf8").split("\n");const s = Number(lines[0]);const out: string[] = [];for (let i = 1; i <= s; i++) { const [n, ...xs] = lines[i].trim().split(/\s+/).map(Number); // JS의 수는 모두 double이라 /는 늘 실수 나눗셈이다(합 10^12도 2^53 안이라 정확하다) const mean = xs.reduce((a, b) => a + b, 0) / n; // 평균을 먼저 구하고 평균과의 차를 제곱해 더한다(두 번 훑기): 큰 수끼리 빼는 일이 없다 const variance = xs.reduce((acc, x) => acc + (x - mean) ** 2, 0) / n; out.push(`${mean.toFixed(3)} ${Math.sqrt(variance).toFixed(3)}`);}console.log(out.join("\n"));
JavaMain.java · 27 줄
import java.io.BufferedReader;import java.io.InputStreamReader;import java.util.Locale;public class Main { public static void main(String[] args) throws Exception { BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); int s = Integer.parseInt(in.readLine().trim()); StringBuilder out = new StringBuilder(); for (int k = 0; k < s; k++) { String[] p = in.readLine().trim().split("\\s+"); int n = Integer.parseInt(p[0]); long[] xs = new long[n]; long sum = 0; // 10^9 × 1,000 = 10^12: int로는 넘친다 for (int i = 0; i < n; i++) { xs[i] = Long.parseLong(p[i + 1]); sum += xs[i]; } double mean = (double) sum / n; // long / int는 정수 나눗셈이라 한쪽을 double로 바꾼다 // 평균을 먼저 구하고 평균과의 차를 제곱해 더한다(두 번 훑기): 큰 수끼리 빼는 일이 없다 double sq = 0; for (long x : xs) sq += (x - mean) * (x - mean); out.append(String.format(Locale.ROOT, "%.3f %.3f", mean, Math.sqrt(sq / n))).append('\n'); } System.out.print(out); }}
C#Main.cs · 27 줄
using System;using System.Globalization;using System.Linq;using System.Text;class Program{ static void Main() { int s = int.Parse(Console.ReadLine()); var sb = new StringBuilder(); for (int k = 0; k < s; k++) { long[] p = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries).Select(long.Parse).ToArray(); int n = (int)p[0]; long[] xs = p.Skip(1).ToArray(); long sum = xs.Sum(); // 10^9 × 1,000 = 10^12: int로는 넘친다 double mean = (double)sum / n; // long / int는 정수 나눗셈이라 한쪽을 double로 바꾼다 // 평균을 먼저 구하고 평균과의 차를 제곱해 더한다(두 번 훑기): 큰 수끼리 빼는 일이 없다 double sq = xs.Sum(x => (x - mean) * (x - mean)); double sd = Math.Sqrt(sq / n); sb.Append(mean.ToString("F3", CultureInfo.InvariantCulture)).Append(' ') .Append(sd.ToString("F3", CultureInfo.InvariantCulture)).Append('\n'); } Console.Write(sb); }}
C++main.cpp · 24 줄
#include <cmath>#include <cstdio>#include <iostream>#include <vector>int main() { int s; std::cin >> s; for (int k = 0; k < s; k++) { int n; std::cin >> n; std::vector<long long> xs(n); long long sum = 0; // 10^9 × 1,000 = 10^12: int로는 넘친다 for (auto& x : xs) { std::cin >> x; sum += x; } double mean = static_cast<double>(sum) / n; // 한쪽을 double로 바꿔야 실수 나눗셈이 된다 // 평균을 먼저 구하고 평균과의 차를 제곱해 더한다(두 번 훑기): 큰 수끼리 빼는 일이 없다 double sq = 0; for (long long x : xs) sq += (x - mean) * (x - mean); std::printf("%.3f %.3f\n", mean, std::sqrt(sq / n)); }}
Cmain.c · 26 줄
#include <math.h>#include <stdio.h>int main(void) { int s; scanf("%d", &s); static long long xs[1000]; for (int k = 0; k < s; k++) { int n; scanf("%d", &n); long long sum = 0; /* 10^9 × 1,000 = 10^12: int(약 21억)로는 넘친다 */ for (int i = 0; i < n; i++) { scanf("%lld", &xs[i]); sum += xs[i]; } double mean = (double)sum / n; /* 한쪽을 double로 바꿔야 실수 나눗셈이 된다 */ /* 평균을 먼저 구하고 평균과의 차를 제곱해 더한다(두 번 훑기): 큰 수끼리 빼는 일이 없다 */ double sq = 0; for (int i = 0; i < n; i++) { double d = xs[i] - mean; sq += d * d; } printf("%.3f %.3f\n", mean, sqrt(sq / n)); } return 0;}
Craykonmain.cray · 20 줄
s = 콘솔.줄읽기().수로변환();반복 (k = 0; k < s; k++){ xs = 콘솔.수들읽기(); n = xs[0]; // 맨 앞은 개수 sum = 0; 반복 (i = 1; i <= n; i++) { sum += xs[i]; } // 크레이콘의 /는 늘 실수 나눗셈이다(정수 몫은 수학.몫) mean = sum / n; // 평균을 먼저 구하고 평균과의 차를 제곱해 더한다(두 번 훑기): 큰 수끼리 빼는 일이 없다 sq = 0; 반복 (i = 1; i <= n; i++) { sq += (xs[i] - mean) * (xs[i] - mean); } 콘솔.쓰기(글자.소수자리맞추기(mean, 3) + " " + 글자.소수자리맞추기(수학.제곱근(sq / n), 3));}