1 条题解
-
0
【例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