问题描述
注:本题目来自2022春HIT-ICS Lab1 程序运行分析(2)浮点数的坑
感觉自己还是用心写了滴,供大家参考~如有不对欢迎指正
给定一段代码:
int main(){
float f;
for(;;){
printf("请输入一个浮点数:");
scanf("%f", &f);
printf("这个浮点数的值是:%f\n",f);
if (f==0) break;
}
return 0;
}
运行输入:
61.419997
61.419998
61.419999
61.420000
61.420001
0
运行输入:
10.186810
10.186811
10.186812
10.186813
10.186814
10.186815
0
请运行程序,并分析程序为什么是这样的执行结果?
程序中浮点数比较、汇总统计等应注意什么呢?
运行结果
现象分析
仅供参考~如有不对欢迎指正
原因:
-
浮点数在计算机中的存储(以单精度为例)是1位符号位、8位阶码、23位尾数组成;
扫描二维码关注公众号,回复: 16649902 查看本文章 -
因为尾数只有23位,而部分十进制小数只能转换成无穷为二进制小数,只能通过截取二进制数满足存储要求,此时涉及到截取后是否舍入的问题;
-
通常采用“向偶数进位的方法”来决定截取后是否舍入;
-
计算机对浮点数61.419997、61.419998、61.419999、61.420000、61.420001按照上述规则进行截断、进位处理后存储在计算机中;这些浮点数二进制表示的符号位和阶码都一样,这里仅展示尾数,如下图所示。可以看到,61.419997、61.419998、61.419999、61.420000的截断后的尾数一样(处于上方的红框),而61.420001与61.420002的尾数一样(处于下方的红框);
-
所以61.419997、61.419998、61.419999、61.420000在计算机中的二进制表示一样,61.420001与61.420002的二进制表示一样;
-
C语言的printf在打印%f格式的数字时,首先将二进制浮点数表示转换为十进制,然后对求得的十进制数字保留小数点后6位,查阅资料得知决定此时是否舍入的依据是四舍五入,而头4个浮点数的二进制表示转换为十进制后,为61.41999816894531,保留6位小数后为61.419998,而61.420001与61.420002的二进制表示转换为十进制后,为61.42000198364258,保留6位小数后为61.420002,与打印出来的结果一致;
-
至于右边的数字(10.18681x)为何能正常显示不出错,其道理同上,这些浮点数的二进制表示的尾数见下图,可以看到尾数各异,而恰好转为十进制并截取小数位时,与原来的结果一样,因而可以正常显示不出错。