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);
}
运行结果如下:(截取了部分)
简单来说,就是:
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;
这样就没问题了。