{ }codelper
四捨五入小数の出力P0232

人数に合わせて変える料理の分量

料理本の分量表を、作る人数に合わせて変える。
一行目に料理本が決めた人数分 b と作る人数分 t が空白一つで区切って与えられる。
二行目に材料の数 n が与えられる。
続く n 行には、一行に材料の名前、料理本の量 a、桁数 d が空白一つずつで区切って与えられる。
変えた量 x は a × t ÷ b を正確に計算した値である。
d が 1 か 2 なら、x を小数第 d 位まで四捨五入し、小数点以下をちょうど d 桁で書く(2.1 は d が 2 なら 2.10)。
d が 0 なら、x を整数に四捨五入し、小数点なしで書く。
d が -1 なら x をいちばん近い 10 の倍数に、d が -2 ならいちばん近い 100 の倍数に四捨五入し、小数点なしで書く(237.8 は d が -1 なら 240)。
四捨五入した結果が 0 なら、その桁数に合わせて 0、0.0、0.00 のように書く。
四捨五入で迷わないように、x に 10^d を掛けた値の小数部分が 0.4 以上 0.6 以下になる入力は与えられない。
材料ごとに入力の順に、一行に材料の名前と変えた量を空白一つで区切って出力せよ。

入力
1 ≤ b ≤ 100、1 ≤ t ≤ 100、1 ≤ n ≤ 1,000、材料の名前は英小文字 1〜20 文字(同じ名前がまた出ることもある)、0.01 ≤ a ≤ 10,000 で a は小数点以下を 0〜2 桁で書く(例:250、1.5、0.75)、d は -2、-1、0、1、2 のいずれか、x × 10^d の小数部分が 0.4〜0.6 になる入力はない
出力
n 行:材料の名前と変えた量
例 1 · stdin
4 6
6
flour 420 -1
milk 330 0
sugar 12.38 1
salt 1.4 2
yeast 0.08 2
butter 55 -2
stdout
flour 630
milk 495
sugar 18.6
salt 2.10
yeast 0.12
butter 100
例 2 · stdin
3 1
4
water 1000 0
pepper 0.5 2
rice 20 -1
tiny 1 -2
stdout
water 333
pepper 0.17
rice 10
tiny 0
main.py
入力(stdin)

実行すると、これらの行が順に input()・標準入力に渡されます(実行中に入力を求めません)。

$ 準備完了

コードを入力して解くにはパソコンで開いてください。モバイルでは問題と解答を見られます。

ほかの言語では?言語別の解答を見る · 8 言語の解答

小数 d 桁にそろえて書く道具は、Python f"{x:.{d}f}"、JS・TS x.toFixed(d)、Java String.format("%." + d + "f", x)、C# x.ToString("F" + d)、C printf("%.*f", d, x)、C++ std::fixed << std::setprecision(d)、Craykon 文字.桁そろえ(x, d) です。
どれも 2.1 を 2.10 のように後ろの 0 まで埋めてくれます。
四捨五入だけをする Python round(x, 2)、Craykon 数学.四捨五入(x, 2)、JS Math.round(x * 100) / 100 は数を返すので、そのまま書くと 2.1 になります。
桁数が 0 以下だと道具ごとに違います。
JS toFixed(-1) は RangeError を出します。
C の %.*f に負の桁数を渡すと桁数なしとみなされ、小数六桁が出ます。
Craykon 数学.四捨五入 は桁数として 0〜10 しか受け取りません。
Python round(x, -1) は使えますが実数を返すので 240.0 と書かれます。
そこで 10^(-d) の単位で割って整数に四捨五入し、また掛けます:Python round(x / 10) * 10(引数一つの round は整数を返します)、JS・TS・Java Math.round、C llround、C++ std::llround、C# (long)Math.Round、Craykon 数学.四捨五入(x / 10) * 10。
倍率も罠です。
C・C++・Java・C# で a * (t / b) と書くと整数どうしの t / b が先に計算され、6 / 4 が 1 になります。
a * t / b のように実数 a から掛ければ実数の割り算になります。
Python 3・JS・TS・Craykon の / はいつも実数の割り算です。
四捨五入の規則も言語ごとに違います。
ちょうど半分の値を Python round と C# Math.Round は偶数のほうへ、JS・Java Math.round は大きいほうへ、C llround・C++ std::llround・Craykon 数学.四捨五入 は 0 から遠いほうへ送ります。
Craykon と Java の書式は見えている十進数を丸めますが、C・C++・Python・JS・C# の書式は二進数で保存された値を丸めます(1.005 → 1.00)。
この問題はそのような境目に近い値を与えないので、どの方法でも答えは同じです。
Java String.format と C# ToString・double.Parse は実行環境の地域設定に従い小数点がコンマになることがあるので、Locale.ROOT・CultureInfo.InvariantCulture を渡します。

Pythonmain.py · 12 行
b, t = map(int, input().split())n = int(input())for _ in range(n):    name, a, d = input().split()    d = int(d)    x = float(a) * t / b  # /는 늘 실수 나눗셈이다    if d > 0:        print(name, f"{x:.{d}f}")    else:        # 자리가 0 이하이면 10^(-d) 단위로: round(x / 단위)는 정수를 돌려준다        step = 10 ** -d        print(name, round(x / step) * step)
JavaScriptmain.js · 16 行
const lines = require("fs").readFileSync(0, "utf8").split("\n");const [b, t] = lines[0].trim().split(/\s+/).map(Number);const n = Number(lines[1]);const out = [];for (let i = 0; i < n; i++) {  const [name, a, ds] = lines[2 + i].trim().split(/\s+/);  const d = Number(ds);  const x = (Number(a) * t) / b;  if (d > 0) {    out.push(`${name} ${x.toFixed(d)}`); // toFixed는 0~100자리만 받는다  } else {    const step = 10 ** -d;    out.push(`${name} ${Math.round(x / step) * step}`);  }}console.log(out.join("\n"));
TypeScriptmain.ts · 17 行
import { readFileSync } from "node:fs";const lines: string[] = readFileSync(0, "utf8").split("\n");const [b, t] = lines[0].trim().split(/\s+/).map(Number);const n = Number(lines[1]);const out: string[] = [];for (let i = 0; i < n; i++) {  const [name, a, ds] = lines[2 + i].trim().split(/\s+/);  const d = Number(ds);  const x: number = (Number(a) * t) / b;  if (d > 0) {    out.push(`${name} ${x.toFixed(d)}`); // toFixed는 0~100자리만 받는다  } else {    const step = 10 ** -d;    out.push(`${name} ${Math.round(x / step) * step}`);  }}console.log(out.join("\n"));
JavaMain.java · 27 行
import java.util.Locale;import java.util.Scanner; public class Main {    public static void main(String[] args) {        Scanner sc = new Scanner(System.in);        int b = sc.nextInt(), t = sc.nextInt();        int n = sc.nextInt();        StringBuilder out = new StringBuilder();        for (int i = 0; i < n; i++) {            String name = sc.next();            double a = Double.parseDouble(sc.next());            int d = sc.nextInt();            double x = a * t / b; // a가 double이라 실수 나눗셈이 된다            out.append(name).append(' ');            if (d > 0) {                // Locale.ROOT: 지역 설정과 상관없이 소수점을 점으로 쓴다                out.append(String.format(Locale.ROOT, "%." + d + "f", x));            } else {                long step = d == 0 ? 1 : d == -1 ? 10 : 100;                out.append(Math.round(x / step) * step);            }            out.append('\n');        }        System.out.print(out);    }}
C#Main.cs · 34 行
using System;using System.Globalization;using System.Text; class Program{    static void Main()    {        var inv = CultureInfo.InvariantCulture;        string[] bt = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries);        int b = int.Parse(bt[0]), t = int.Parse(bt[1]);        int n = int.Parse(Console.ReadLine());        var out_ = new StringBuilder();        for (int i = 0; i < n; i++)        {            string[] p = Console.ReadLine().Split(' ', StringSplitOptions.RemoveEmptyEntries);            double a = double.Parse(p[1], inv);            int d = int.Parse(p[2]);            double x = a * t / b;            out_.Append(p[0]).Append(' ');            if (d > 0)            {                out_.Append(x.ToString("F" + d, inv)); // "F2": 소수 두 자리            }            else            {                long step = d == 0 ? 1 : d == -1 ? 10 : 100;                out_.Append((long)Math.Round(x / step) * step);            }            out_.Append('\n');        }        Console.Write(out_);    }}
C++main.cpp · 23 行
#include <cmath>#include <iomanip>#include <iostream>#include <string> int main() {    int b, t, n;    std::cin >> b >> t >> n;    for (int i = 0; i < n; i++) {        std::string name;        double a;        int d;        std::cin >> name >> a >> d;        double x = a * t / b;        std::cout << name << ' ';        if (d > 0) {            std::cout << std::fixed << std::setprecision(d) << x << '\n';        } else {            long long step = d == 0 ? 1 : d == -1 ? 10 : 100;            std::cout << std::llround(x / step) * step << '\n';        }    }}
Cmain.c · 21 行
#include <math.h>#include <stdio.h> int main(void) {    int b, t, n;    scanf("%d %d %d", &b, &t, &n);    for (int i = 0; i < n; i++) {        char name[32];        double a;        int d;        scanf("%31s %lf %d", name, &a, &d);        double x = a * t / b; /* a가 double이라 실수 나눗셈이 된다 */        if (d > 0) {            printf("%s %.*f\n", name, d, x); /* 자리 수를 인수로 넘긴다 */        } else {            long long step = d == 0 ? 1 : d == -1 ? 10 : 100;            printf("%s %lld\n", name, llround(x / step) * step);        }    }    return 0;}
Craykonmain.cray · 27 行
bt = コンソール.数読み();b = bt[0];t = bt[1];n = コンソール.行読み().数に();繰り返す (i = 0; i < n; i++){    p = コンソール.行読み().分ける();    a = p[1].数に();    d = p[2].数に();    x = a * t / b; // 크레이콘의 / 는 늘 소수까지 나눈다    값 = "";    もし (d > 0)    {        값 = 文字.桁そろえ(x, d);    }    でなければ    {        // 수학.반올림의 자리는 0~10만 된다: 10, 100 단위는 나눠서 반올림하고 다시 곱한다        step = 1;        繰り返す (k = 0; k < 0 - d; k++)        {            step *= 10;        }        값 = 数学.四捨五入(x / step) * step;    }    コンソール.書く(p[0] + " " + 값);}