银行家舍入

按字符串读取一位小数,分别实现普通四舍五入和向偶数舍入。

OJ: shumeng

题目 ID: CSP202605A

难度:未知

标签:字符串模拟浮点数

日期: 2026-07-31 16:22

形式化题目

给定 nn 个形如 xxx.x 的非负实数,整数部分 aa 为任意非负整数,小数部分 bb 为一位数字。对每个数分别计算两种取整结果:

  • 四舍五入:b4b\le 4aab5b\ge 5a+1a+1
  • 银行家舍入(向偶数舍入):b<5b<5aab>5b>5a+1a+1b=5b=5 时若 aa 为偶数取 aa、否则取 a+1a+1

思路

避免浮点误差

读入一律按字符串处理,在小数点处切分得到整数部分和小数部分,避免 double 解析带来的精度问题。

两种规则只有半整数不同

两种规则在小数位为 040\sim4 时都向下取整,696\sim9 时都进位,唯一的区别出现在 b=5b=5:四舍五入一律进位,银行家舍入只在整数部分为奇数时进位。判断奇偶用 integer_part & 1 即可。

代码

cpp
/**
 * Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
 * rbook: -> https://rbook.roj.ac.cn  https://rbook2.roj.ac.cn
 * rainboy的学习导航网站: https://idx.roj.ac.cn
 * create_at: 2026-07-31 16:22
 * update_at: 2026-08-17 22:40
 */
#include <bits/stdc++.h>
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n;
    cin >> n;
    vector<long long> normal(n); // 普通四舍五入的结果
    vector<long long> banker(n); // 银行家舍入的结果
    for (int i = 0; i < n; i++) {
        string value;
        cin >> value;
        // 按字符串切分,避免浮点解析误差
        size_t dot = value.find('.');
        long long integer_part = stoll(value.substr(0, dot));
        int decimal_part = value[dot + 1] - '0';

        // 普通四舍五入:小数位 >= 5 进位
        normal[i] = integer_part + (decimal_part >= 5);

        // 银行家舍入:小数位 > 5 进位;等于 5 时向偶数靠拢
        banker[i] = integer_part;
        if (decimal_part > 5 || (decimal_part == 5 && (integer_part & 1))) {
            banker[i]++;
        }
    }

    for (int i = 0; i < n; i++) {
        if (i) cout << ' ';
        cout << normal[i];
    }
    cout << '\n';
    for (int i = 0; i < n; i++) {
        if (i) cout << ' ';
        cout << banker[i];
    }
    cout << '\n';
    return 0;
}

复杂度

  • 时间:每个数只扫描一次字符串,设整数部分总长度为 LL,时间复杂度为 O(L)O(L)
  • 空间:需要保存两种结果各 nn 个,空间复杂度 O(n)O(n)

总结

半整数是两种舍入规则唯一不同的地方,直接按题面判断整数部分的奇偶性即可,不需要依赖语言内置的 round()(其策略可能不同)。