1 条题解

  • 0
    @ 1978-1-23 4:52:16

    【例14.2】 四舍六入五留双

    解题思路

    用字符串精确保存小数,保留前 d 位,检查下一位:小于 5 不进位,大于 5 进位;等于 5 时若后面还有非零位则进位,恰好中点则让保留末位成为偶数。

    正确性说明

    去掉部分决定真实值位于中点两侧还是恰在中点;分别使用就近与中点取偶规则。字符串按十进制判断不受二进制浮点误差影响。

    易错点

    5 后有非零数字并非恰好一半;进位可能连锁到整数部分;必须补足 d 位。

    复杂度

    输入长度 L,时间 O(L),空间 O(L)。

    参考代码(C++11)

    #include <bits/stdc++.h>
    using namespace std;
    
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        string s;
        int d;
        cin >> s >> d;
        size_t dot = s.find('.');
        string whole = dot == string::npos ? s : s.substr(0, dot),
               frac = dot == string::npos ? "" : s.substr(dot + 1);
        while (int(frac.size()) <= d)
            frac += '0';
        string keep = whole + frac.substr(0, d);
        bool tail = false;
        for (size_t i = d + 1; i < frac.size(); i++)
            if (frac[i] != '0')
                tail = true;
        bool up = frac[d] > '5' || (frac[d] == '5' && (tail || (keep.back() - '0') % 2));
        if (up) {
            int i = keep.size() - 1;
            while (i >= 0 && keep[i] == '9') {
                keep[i] = '0';
                i--;
            }
            if (i >= 0)
                keep[i]++;
            else
                keep = "1" + keep;
        }
        cout << keep.substr(0, keep.size() - d) << "." << keep.substr(keep.size() - d)
             << "\n";
        return 0;
    }
    
    • 1

    信息

    ID
    568
    时间
    1000ms
    内存
    64MiB
    难度
    普及−
    标签
    递交数
    0
    已通过
    0
    上传者