这一道题要排坑的是关于精度的问题。
题目很简单,要做的只有一下三点:
- 读数据
- 加数据
- 输数据
在C
中,常用的输入方式有scanf()
和cin
。首先我们以scanf()
函数进行讲解,因为这两种输入方式的判断结束方式不一样。
使用sacnf()
函数
scanf()
函数其在输入结束(即读不到数据时)将返回常数EOF
(即-1),而读到数据时会返回读到数据的个数。所以我们可以得出第一版代码:
#include<bits/stdc .h>
using namespace std;
long double ans,tmp;
int main()
{
while((scanf("%Lf",&tmp))!=EOF)
{
ans =tmp;
}
printf("%.5f",ans);
return 0;
}
Tips: scanf()
函数输入long double
类型时需使用%Lf
占位符,但printf()
函数无论输出float
类型还是long double
类型,均使用%f
占位符。
代码已经写完,交上去却只有20分。
我们可以写个程序来测试一下:
代码语言:javascript复制#include<bits/stdc .h>
using namespace std;
long double tmp=1919810.1145142233;
int main(){
printf("%.20Lf",tmp);
return 0;
}
得到的输出是1919810.11451422329992055893
,而不是我们预想的1919810.1145142233
差的不是一丁半点。所以基本上可以判断为精度问题。
所以,我们需要先将它转换为整数,随后再转换回小数,以此确保精度不会出错。
代码语言:javascript复制#include<bits/stdc .h>
using namespace std;
long double ans,tmp;
int main()
{
while((scanf("%Lf",&tmp))!=EOF)//判断是否结束
{
ans =tmp*1000000;//化成整数,防止小数的精度问题
}
printf("%.5Lf",ans/1000000);//转换回小数
return 0;
}
由于每个数最多只有666位小数,所以这里只需要将读入的小数×1000000times 1000000×1000000,就可以转换为整数,最后因为每个数都×1000000times 1000000×1000000,所以我们只需要将最终的答案÷1000000div 1000000÷1000000,就可以恢复了。
使用cin
前面已经说明了具体的算法,故此处不再阐述。
cin
读取完毕后,会直接返回000,而不是如同scanf()
返回的EOF
常数。所以,只需要修改判空部分:
#include<bits/stdc .h>
using namespace std;
long double ans,tmp;
int main()
{
while((cin>>tmp)!=0)//判断是否结束,可以化简成while(cin>>tmp)
{
ans =tmp*1000000;
}
cout<<fixed<<setprecision(5)<<ans/1000000;//使用cout保留小数
return 0;
}
Q&A
Q: 为什么用了你的代码没有输出啊?
A: 您在使用标准输入输出时,程序并不知道你接下来还要不要输入,故无法判断输入是否结束。所以你需要向程序发送一个“信号”,告诉程序输入已经终止。在Windows下,这个“信号”为在程序框中输入Ctrl Z
再按回车,而在类Unix
系统下,这个“信号”为直接按Ctrl D
。