CCF-CSP -201612-2 工资计算 java 实现

本文详细解析了CCFCSP竞赛中的一道工资计算题目,通过实例解释了如何根据税后工资逆推税前工资的过程,同时分享了在处理浮点数运算时可能遇到的精度问题及解决方法。

CCFCSP的1-2题很简单。但是这里又在很简单的问题上翻船了。这里记录一下吧!

试题

试题编号: 201612-2
试题名称: 工资计算
时间限制: 1.0s
内存限制: 256.0MB
问题描述:
  小明的公司每个月给小明发工资,而小明拿到的工资为交完个人所得税之后的工资。
税后工资T = 税前工资S元 - 个人所得税f(S);
S = f(S) + T;
所有评测数据保证小明的税前工资为一个整百的数。
假设他一个月的税前工资(扣除五险一金后、未扣税前的工资)为S元,则他应交的个人所得税按如下公式计算:
  1) 个人所得税起征点为3500元,若S不超过3500,则不交税,3500元以上的部分才计算个人所得税,令A=S-3500元;
  2) A中不超过1500元的部分,税率3%;
  3) A中超过1500元未超过4500元的部分,税率10%;
  4) A中超过4500元未超过9000元的部分,税率20%;
  5) A中超过9000元未超过35000元的部分,税率25%;
  6) A中超过35000元未超过55000元的部分,税率30%;
  7) A中超过55000元未超过80000元的部分,税率35%;
  8) A中超过80000元的部分,税率45%;
  例如,如果小明的税前工资为10000元,则A=10000-3500=6500元,其中不超过1500元部分应缴税1500×3%=45元,超过1500元不超过4500元部分应缴税(4500-1500)×10%=300元,超过4500元部分应缴税(6500-4500)×20%=400元。总共缴税745元,税后所得为9255元。
  已知小明这个月税后所得为T元,请问他的税前工资S是多少元。
输入格式
  输入的第一行包含一个整数T,表示小明的税后所得。所有评测数据保证小明的税前工资为一个整百的数。
输出格式
  输出一个整数S,表示小明的税前工资。
样例输入
9255
样例输出
10000
评测用例规模与约定
  对于所有评测用例,1 ≤ T ≤ 100000。

这个问题并不复杂。简单分析一下:
工资的计算公式如下:
T = S - tax
其中,T为税后工资,S为税前工资,tax为需缴纳的税款,并且tax与S存在函数关系:
tax = f(S)
这个函数就是一个简单的分段函数:几个节点如下表:

StaxT
100001000
350003500
3500+1500=50001500*3% = 454955
5000+3000=800045+3000*10%=3457655
8000+4500=12500345+4500*20%=124511255
12500+26000=385001245+26000*25%=774530755
38500+20000=585007745+20000*30%=1374544755
58500+25000=8350013745+25000*35%=2249561005
9000022495+(90000-83500)*45%=2542064580

另外需要注意的是,题目中对S的限定

所有评测数据保证小明的税前工资为一个整百的数。

这是一个比较有用的信息,大大简化了程序。
分析到这,就可以写代码了。
首先是我第一版的(出错的)代码:

import java.util.*;
public class Main{

    public static void main(String args[]){
        Scanner cin = new Scanner(System.in);
        int T = cin.nextInt();//税后工资
        double S = 0;//税前工资
        if(T <= 3500)
            S = T;
        else if(T <=4955){
            S = (T-105)/0.97;
        }else if(T <=7655){
            S = (T-455)/0.9;
        }else if(T <=11255){
            S = (T-1255)/0.8;
        }else if(T <=30755){
            S = (T-1880)/0.75;
        }else if(T <=44755){
            S = (T-3805)/0.7;
        }else if(T <=61005){
            S = (T-6730)/0.65;
        }else{
            S = (T-15080)/0.55;
        }
        System.out.println((int)S);
    }
}

这段代码提交以后,就会报说是错误,给了80分。我之前找了很久,也没发现是哪错了。这几天重新看了一下,才发现了问题。我写了一个Check程序,

for(int i = 1; i < 1001; i++){
            S = i * 100;//税前工资都是整百的!
            T = calT(S);//由税前工资计算税后工资
            s = calS(T);//反推税前工资,看看是否一致;
            if (s != S) //如果不一致,报出来!
                System.out.println("when S = " + S + ",T = " + T + ", s=" +s);
        }

运行结果如下:(截取了部分)
error

简单来说,就是:
55 /0.55 并没有输出100。0,而是输出了99.99999999999
这样后面强制转换,向下取整,自然就是小1了!
网上搜了一下,
http://bbs.youkuaiyun.com/topics/390152581
也遇到了这个问题。

其主要原因是浮点数值采用二进制系统表示, 而在二进制系统中无法精确的表示分数 1/10。 这就好像十进制无法精确地表示 1/3 一样。 如果需要在数值计算中不含有任何舍入误差, 就应该使用BigDecimal 类。——《Java核心技术 卷1》

由上原因,表现出来的就是浮点数的计算结果围绕理论值上下波动
程序中的错误,就是因为当计算值偏大时,取整后,结果正是我们想要的,没有问题;可是当结果偏小时,取整后,就会比理论值小1。因此加上加上下面这一行,避免浮点数除法造成的影响。结果就对了!
因此以后遇到浮点值运算的时候,一定要记得处理这个。
回到工资计算这个问题中,对计算结果,加了下面呢一行代码:

int ss = ((int)S +1) / 100 * 100;

这样就没问题了。

### CCF CSP Java 考试备考资料与认证信息 #### 关于CCF CSP认证 中国计算机学会推出的CCF CSP认证旨在评估软件开发者的实际编程能力,每年别在3月、9月和12月举行三次认证考试[^1]。 #### 编程语言的选择 对于希望使用Java参加CCF CSP认证的考生,在报名时可以选择ALL作为考试语言选项。这意味着可以在不同的题目中自由选择包括但不限于Java在内的多种编程语言来解答问题[^3]。 #### 准备材料推荐 为了更好地准备基于JavaCCF CSP认证: - **官方资源**:定期访问官方网站获取最新的公告和技术文档更新;利用官网提供的历年真题进行实战演练。 - **书籍** - *《算法导论》*:深入理解数据结构和经典算法设计原理。 - *《Effective Java》*:掌握高效编写高质量Java程序的最佳实践指南。 - **在线课程平台** - LeetCode, Codeforces等网站提供了丰富的竞赛级编程挑战,有助于提高解题速度和准确性。 - Coursera上的专项课程如“Algorithms Specialization”,能够帮助巩固理论基础并学习更多高级主题。 - **模拟环境搭建** 使用本地集成开发环境(IDE),比如IntelliJ IDEA Ultimate Edition 或 Eclipse IDE for Java Developers 来熟悉真实的编码场景,并确保所写的代码能够在标准Java运行环境中正常工作。 ```java // 示例:简单的HelloWorld.java文件用于验证编译器配置是否正确 public class HelloWorld { public static void main(String[] args) { System.out.println("Hello World!"); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值