[洛谷 3954][NOIP2017普及组]成绩

题目链接

https://www.luogu.org/problemnew/show/P3954

题解

其实作为第一题而言,这题基本没有难度,不过有个坑的地方,就是浮点误差,光这个问题,就足够我们讨论上一番了。

何谓浮点误差?就是浮点数运算产生的误差。例如本来结果应该是1,结果变成了0.9999999。

接下来的两个程序,其实都是正确(官方评测的时候如此)的,但第一个产生了浮点误差问题,不算完美。

程序1:

#include <stdio.h>
int a,b,c,score;
int main()
{
 scanf("%d%d%d",&a,&b,&c);
 score=a*0.2+b*0.3+c*0.5;
 printf("%d",score);
 return 0;
}

 

如果程序是这样的话,那么样例2输出的结果会是78,而不是79。

为了解释如此诡异(其实也不算诡异)的现象,这里放一下调试的中间结果。

纳尼?12+27+40=79啊,怎么最后输出了78呢?

这里就是浮点误差的产物了,事实上,12+27+40=78.9999…虽然这里没有显示出来,但计算机内部存储的就是这个数,由于浮点数转整数时要截尾(就是舍弃小数点后面的数字),于是结果就是78了。

这现象实在诡异啊,比赛当时首先打了上面的程序,结果出来个78,实在让人吓死了,毕竟第一题就出bug,实在不是什么好兆头。

不过有一种方法可以避免这样的bug。

程序2:

#include <stdio.h>
int a,b,c,score;
int main()
{
 scanf("%d%d%d",&a,&b,&c);
 score=a/5+b/10*3+c/2;
 printf("%d",score);
 fclose(stdin);
 fclose(stdout);
 return 0;
}

这里由于采用了整数运算(别忘了a,b,c都是10的整数倍),避开了浮点误差,这时候程序就能正确输出了。

不过,写了程序1也不存在问题,至少今年是这样的,毕竟CCF放话了:

所以我们讨论了一番,貌似没有什么卵用唉。

且慢!现在是普及组,所以官方仁慈为我们排除了这个问题,以后难免还是会出现要排除浮点误差的情形的,所以学会避开这一点还是有意义的。

所以现在得出一个重要经验:能整数运算的,最好不要用浮点运算。否则真的会产生风险。

唉,现在真是的,普及第一题竟然都有这么多坑了,表示以后还咋办呢。

发表评论

电子邮件地址不会被公开。 必填项已用*标注