舍入(PAT乙级)

PAT乙级 舍入

作者 陈越

单位 浙江大学

不同的编译器对浮点数的精度有不同的处理方法。常见的一种是“四舍五入”,即考察指定有效位的后一位数字,如果不小于 5,就令有效位最后一位进位,然后舍去后面的尾数;如果小于 5 就直接舍去尾数。另一种叫“截断”,即不管有效位后面是什么数字,一概直接舍去。还有一种是“四舍六入五成双”,即当有效位的后一位数字是 5 时,有 3 种情况要考虑:如果 5 后面还有其它非 0 尾数,则进位;如果没有,则当有效位最后一位是单数时进位,双数时舍去,即保持最后一位是双数。

本题就请你写程序按照要求处理给定浮点数的舍入问题。

输入格式:

输入第一行给出两个不超过 100 的正整数 N 和 D,分别是待处理数字的个数和要求保留的小数点后的有效位数。随后 N 行,每行给出一个待处理数字的信息,格式如下:

指令符 数字

其中指令符是表示舍入方法的一位数字,1 表示“四舍五入”,2 表示“截断”,3 表示“四舍六入五成双”;数字是一个总长度不超过 200 位的浮点数,且不以小数点开头或结尾,即 0.123 不会写成 .123123 也不会写成 123.。此外,输入保证没有不必要的正负号(例如 -0.0+1)。

输出格式:

对每个待处理数字,在一行中输出根据指令符处理后的结果数字。

输入样例:

7 3
1 3.1415926
2 3.1415926
3 3.1415926
3 3.14150
3 3.14250
3 3.14251
1 3.14

输出样例:

3.142
3.141
3.142
3.142
3.142
3.143
3.140

 题目分析:

题目看上去很简单,但是有非常多的细节需要处理,题目中说到“输入保证没有不必要的正负号(例如 -0.0+1)”,这句话其实是在提醒我们需要对负数进行特殊处理,并且输出的时候可能会出现不必要的负号。具体细节请看源代码中的注释。

Python3

def fun1(s,cnt): # 截取
    zs,xs = s.split(".")
    return zs + '.' + xs[:cnt]


def fun2(s,cnt): # 进位
    zs,xs = s.split(".")
    xs = str(int(xs[:cnt])+1)
    if len(xs) > cnt:
        zs = str(int(zs)+1) if int(zs) >= 0 else str(int(zs)-1) # 注意负数的时候整数部分应该减一,测试点7
        xs = "0" * cnt
    elif len(xs) < cnt: # 把原先的前导0补回来,测试点7
        xs = "0" * (cnt - len(xs)) + xs
    return zs + '.' + xs


n, d = map(int,input().split())
for i in range(n):
    op, num = input().split()
    op = int(op)
    if "." not in num: # num是整数 测试点2,6
        print(num+'.'+"0"*d)
        continue
    zs,xs = num.split(".")
    if len(xs) <= d: # num的小数位数本身就小于等于d
        print(num+'0'*(d-len(xs)))
    else:
        if op == 1:
            if int(xs[d]) < 5:
                res = fun1(num,d)
            else:
                res = fun2(num,d)
        elif op == 2:
            res = fun1(num,d)
        elif op == 3:
            # 有效位的后一位小于5 或 (有效位的有一位是5 且 5后面没有其它非零尾数 且 有效位的前一位数字是偶数)
            if int(xs[d]) < 5 or (int(xs[d]) == 5 and (len(xs) == d + 1 or int(xs[d+1:]) == 0) and int(xs[d-1]) % 2 == 0):
                res = fun1(num,d)
            else:
                res = fun2(num,d)
        if eval(res) == 0 and res[0] == '-': # 注意舍入后出现-0的情况,测试点8
            res = res[1:]
        print(res)

C++

根据上述python代码由GPT生成,测试点7运行时错误

#include <iostream>
#include <string>
#include <iomanip>
using namespace std;

// 截取函数
string fun1(string s, int cnt) {
    size_t dot_pos = s.find('.');
    string zs = s.substr(0, dot_pos);  // 整数部分
    string xs = s.substr(dot_pos + 1); // 小数部分
    return zs + '.' + xs.substr(0, cnt);
}

// 进位函数
string fun2(string s, int cnt) {
    size_t dot_pos = s.find('.');
    string zs = s.substr(0, dot_pos);  // 整数部分
    string xs = s.substr(dot_pos + 1); // 小数部分

    // 取小数的前cnt位,并将它转为整数后加1
    int carry = stoi(xs.substr(0, cnt)) + 1;
    xs = to_string(carry);

    if (xs.length() > cnt) {  // 进位到整数部分
        if (zs[0] == '-') {  // 处理负数进位的情况
            int zs_int = stoi(zs);
            zs_int -= 1;  // 负数情况下,整数部分减1
            zs = to_string(zs_int);
        } else {
            int zs_int = stoi(zs);
            zs_int += 1;  // 正数情况下,整数部分加1
            zs = to_string(zs_int);
        }
        xs = string(cnt, '0'); // 小数位补零
    } else if (xs.length() < cnt) {  // 补回前导0
        xs = string(cnt - xs.length(), '0') + xs;
    }

    return zs + '.' + xs;
}

int main() {
    int n, d;
    cin >> n >> d; // 读取n和d

    for (int i = 0; i < n; ++i) {
        int op;
        string num;
        cin >> op >> num;  // 读取操作类型和数字

        if (num.find('.') == string::npos) {  // 整数情况
            cout << num + '.' + string(d, '0') << endl;
            continue;
        }

        size_t dot_pos = num.find('.');
        string zs = num.substr(0, dot_pos);     // 整数部分
        string xs = num.substr(dot_pos + 1);    // 小数部分

        if (xs.length() <= d) {  // 小数位数小于等于d
            cout << num + string(d - xs.length(), '0') << endl;
        } else {
            string res;
            if (op == 1) {
                if (xs[d] < '5') {
                    res = fun1(num, d); // 截取
                } else {
                    res = fun2(num, d); // 进位
                }
            } else if (op == 2) {
                res = fun1(num, d); // 直接截取
            } else if (op == 3) {
                if (xs[d] < '5' || (xs[d] == '5' && (xs.length() == d + 1 || stoi(xs.substr(d + 1)) == 0) && (xs[d - 1] - '0') % 2 == 0)) {
                    res = fun1(num, d); // 截取
                } else {
                    res = fun2(num, d); // 进位
                }
            }

            // 处理舍入后的 -0 问题
            if (stod(res) == 0 && res[0] == '-') {
                res = res.substr(1);  // 去掉负号
            }

            cout << res << endl;
        }
    }

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值