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

版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/sunjinshengli/article/details/78820845

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)
这个函数就是一个简单的分段函数:几个节点如下表:

S tax T
1000 0 1000
3500 0 3500
3500+1500=5000 1500*3% = 45 4955
5000+3000=8000 45+3000*10%=345 7655
8000+4500=12500 345+4500*20%=1245 11255
12500+26000=38500 1245+26000*25%=7745 30755
38500+20000=58500 7745+20000*30%=13745 44755
58500+25000=83500 13745+25000*35%=22495 61005
90000 22495+(90000-83500)*45%=25420 64580

另外需要注意的是,题目中对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.csdn.net/topics/390152581
也遇到了这个问题。

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

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

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

这样就没问题了。

猜你喜欢

转载自blog.csdn.net/sunjinshengli/article/details/78820845