{ }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()/标准输入传入(运行中不会等待输入)。

$ 就绪

请在电脑上打开以编写和运行代码。在手机上可以查看题目和题解。

其他语言怎么写?查看各语言题解 · 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。
Craykon 控制台.输出 同样不写末尾的 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);}