{ }codelper
소수 자리 출력P0221

저울에 뜨는 무게

가게 저울은 물건을 올리거나 내릴 때마다 올라가 있는 무게의 합을 킬로그램으로 보여 준다. 처음에는 저울에 아무것도 없다. 첫 줄에 무게가 바뀐 횟수 n이 주어진다. 다음 n줄에 바뀐 무게 w가 한 줄에 하나씩, 바뀐 차례대로 주어진다. w가 양수이면 그만큼 올린 것이고, 음수이면 그만큼 내린 것이다. w는 정수이거나 소수점 아래 1~3자리까지 쓴 수다(예: 2, 0.5, -1.25, 0.125, 1.500). 무게가 바뀔 때마다 저울이 보여 주는 합을 한 줄씩 출력하라. 저울이 보여 주는 합은 그때까지 주어진 w를 모두 정확히 더한 값이다. 합은 소수점 아래 끝의 0을 지우고 쓴다(1.250 → 1.25). 소수 부분이 모두 0이면 소수점도 쓰지 않는다(2.000 → 2). 합이 1보다 작으면 소수점 앞에 0을 쓴다(0.5이지 .5가 아니다). 합이 0이면 0이라고 쓴다(-0이 아니다). 내리는 무게는 올라가 있는 무게보다 많지 않아서, 정확한 합은 늘 0 이상이다.

입력
1 ≤ n ≤ 1,000, -100 ≤ w ≤ 100, w ≠ 0, w는 소수점 아래 0~3자리, 정확한 합은 늘 0 이상
출력
n줄, 줄마다 그때의 합(끝의 0과 남은 소수점을 지운 꼴)
예시 1 · stdin
3
0.1
0.2
-0.3
stdout
0.1
0.3
0
예시 2 · stdin
5
2
0.5
-1.25
0.125
0.875
stdout
2
2.5
1.25
1.375
2.25
main.py
입력(stdin)

실행하면 이 줄들이 차례로 input()·표준 입력으로 들어가요(실행 중에 묻지 않아요).

$ 준비됐어요

코드를 입력해 풀려면 PC에서 열어 주세요. 모바일에서는 문제와 풀이를 볼 수 있어요.

다른 언어로는?언어별 풀이 보기 · 8개 언어 풀이

실수를 더하면 생기는 작은 오차를 사람이 읽는 꼴로 찍는 문제예요.
0.1과 0.2는 이진수로 정확히 담기지 않아서 0.1 + 0.2는 0.30000000000000004가 돼요.
그냥 찍으면 Python print(x)와 JS·TS console.log(x)는 0.30000000000000004를 찍고, Python과 Java는 2도 2.0으로 찍어요.
그래서 먼저 소수 셋째 자리까지 맞춘 문자열을 만들어요: Python f"{x:.3f}", C snprintf(buf, sizeof buf, "%.3f", x), C++ std::fixed << std::setprecision(3), Java String.format(Locale.ROOT, "%.3f", x), C# x.ToString("F3", CultureInfo.InvariantCulture).
그다음 끝의 0을 지우고, 소수점만 남으면 그것도 지워요(Python .rstrip("0").rstrip("."), C# .TrimEnd('0').TrimEnd('.')).
0만 지우면 2.000이 2.이 돼요.
C의 %g도 끝의 0을 지워 주지만 유효 숫자를 6개까지만 써서 99999.999를 100000으로 찍어요.
둘째 함정은 -0이에요.
0.3 - 0.1 - 0.2는 0이 아니라 -0.0000000000000000277이라서, 셋째 자리로 찍으면 C·C++·Python·Java·C#(.NET Core 3.0부터)·JS의 toFixed 모두 -0.000이 나와요.
지운 결과가 -0이면 0으로 바꿔요(Python 3.11부터는 f"{x:z.3f}"의 z가 -0을 0으로 찍어 줘요).
JS·TS는 Math.round(x * 1000) / 1000으로 수를 맞춘 뒤 그대로 찍어도 돼요.
수를 문자열로 바꿀 때 끝의 0을 쓰지 않고, -0도 0으로 쓰기 때문이에요.
크레이콘 콘솔.쓰기도 끝의 0 없이 찍고, 소수 아홉째 자리까지 반올림해 찍어서 0.1 + 0.2도 0.3으로 보여 줘요.
하지만 큰 무게를 수백 번 더해 쌓인 오차는 다 가리지 못해서(99.999를 491번 더하면 49099.509000001) 셋째 자리로 먼저 맞춰야 해요: 수학.내림(x * 1000 + 0.5) / 1000.
오차가 아예 싫다면 무게를 1000배 한 정수(그램)로 더하는 방법도 있어요.

Pythonmain.py · 11 줄
n = int(input())total = 0.0out = []for _ in range(n):    total += float(input())    # 소수 셋째 자리까지 찍고 끝의 0과 남은 소수점을 지운다    s = f"{total:.3f}".rstrip("0").rstrip(".")    if s == "-0":          # 0 바로 아래의 작은 오차는 "-0.000"으로 찍힌다        s = "0"    out.append(s)print("\n".join(out))
JavaScriptmain.js · 11 줄
const lines = require("fs").readFileSync(0, "utf8").split("\n");const n = Number(lines[0]);let total = 0;const out = [];for (let i = 1; i <= n; i++) {  total += Number(lines[i]);  // 1000분의 1로 반올림한 수를 그대로 찍으면 끝의 0이 없다(2.5, 2). -0도 "0"으로 찍힌다  const shown = Math.round(total * 1000) / 1000;  out.push(String(shown));}console.log(out.join("\n"));
TypeScriptmain.ts · 12 줄
import { readFileSync } from "node:fs";const lines: string[] = readFileSync(0, "utf8").split("\n");const n: number = Number(lines[0]);let total = 0;const out: string[] = [];for (let i = 1; i <= n; i++) {  total += Number(lines[i]);  // 1000분의 1로 반올림한 수를 그대로 찍으면 끝의 0이 없다(2.5, 2). -0도 "0"으로 찍힌다  const shown: number = Math.round(total * 1000) / 1000;  out.push(String(shown));}console.log(out.join("\n"));
JavaMain.java · 22 줄
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.util.Locale; public class Main {    public static void main(String[] args) throws IOException {        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));        int n = Integer.parseInt(in.readLine().trim());        double total = 0;        StringBuilder out = new StringBuilder();        for (int i = 0; i < n; i++) {            total += Double.parseDouble(in.readLine().trim());            // Double.toString은 2.0처럼 찍으니 소수 셋째 자리로 찍고 끝의 0을 지운다            String s = String.format(Locale.ROOT, "%.3f", total);            s = s.replaceAll("0+$", "").replaceAll("\\.$", "");            if (s.equals("-0")) s = "0";            out.append(s).append('\n');        }        System.out.print(out);    }}
C#Main.cs · 22 줄
using System;using System.Globalization;using System.Text; class Program{    static void Main()    {        int n = int.Parse(Console.ReadLine());        double total = 0;        var sb = new StringBuilder();        for (int i = 0; i < n; i++)        {            total += double.Parse(Console.ReadLine(), CultureInfo.InvariantCulture);            // "F3"으로 셋째 자리까지 찍고 끝의 0과 소수점을 지운다            string s = total.ToString("F3", CultureInfo.InvariantCulture).TrimEnd('0').TrimEnd('.');            if (s == "-0") s = "0";            sb.Append(s).Append('\n');        }        Console.Write(sb);    }}
C++main.cpp · 24 줄
#include <iomanip>#include <iostream>#include <sstream>#include <string> int main() {    std::ios::sync_with_stdio(false);    int n;    std::cin >> n;    double total = 0;    for (int i = 0; i < n; i++) {        double w;        std::cin >> w;        total += w;        std::ostringstream os;        os << std::fixed << std::setprecision(3) << total;        std::string s = os.str();        // 끝의 0과 남은 소수점을 지운다        while (s.back() == '0') s.pop_back();        if (s.back() == '.') s.pop_back();        if (s == "-0") s = "0";        std::cout << s << "\n";    }}
Cmain.c · 22 줄
#include <stdio.h>#include <string.h> int main(void) {    int n;    double w, total = 0;    char buf[64];    scanf("%d", &n);    for (int i = 0; i < n; i++) {        scanf("%lf", &w);        total += w;        snprintf(buf, sizeof buf, "%.3f", total);        /* 끝의 0을 지우고, 소수점만 남으면 그것도 지운다 */        size_t len = strlen(buf);        while (buf[len - 1] == '0') len--;        if (buf[len - 1] == '.') len--;        buf[len] = '\0';        if (strcmp(buf, "-0") == 0) strcpy(buf, "0");        puts(buf);    }    return 0;}
Craykonmain.cray · 9 줄
n = 콘솔.줄읽기().수로변환();total = 0;반복 (i = 0; i < n; i++){    total += 콘솔.줄읽기().공백제거().수로변환();    // 1000분의 1 단위로 맞춘다. 쓰기는 끝의 0 없이 찍는다(2.5, 2)    shown = 수학.내림(total * 1000 + 0.5) / 1000;    콘솔.쓰기(shown);}