小数为什么有误差?

来源:互联网 发布:linux oracle 查看sid 编辑:程序博客网 时间:2024/05/01 10:50
#include<stdio.h>
int main()
{
int a=12;
float b=702.1;
printf("%e,%d,/n",a,a);
printf("%e,%f,/n",b,b);
}

我在最近发现,这里面的输出都有问题。。
如上面代码所示,应该输出的是
12(指数类型),12
702.1(指数类型),702.10000

但结果确实这样 :
2.546395e-313,4199189
7.021000e+002,702,099976
==================================================================

首先看printf("%e,%d,/n",a,a);这行代码,“%e”表示以指数方式输出浮点数,所以printf函数就认为你输入的数字float类型,不幸的是你的这里给的是int类型的a,因为printf函数就被骗了,所以输出了乱七八糟的数字,而且也殃及池鱼到了后边的“%d”。我们可以说printf有点傻,也可以说我们应该严格按照函数的约定来进行调用。千万不要因为认为“int就是一种float”,只是“int能够与float兼容”而已。int和float是不同的数据类型。
你试着运行一下这句代码:printf("%e,%d,/n",(float)a,a);。看看是不是得到了你预想的效果?

printf("%e,%f,/n",b,b);
%e就是表示以指数的方式输出的,所以输出“***e***”是正确的。

float输出误差现象这就涉及到数字在计算机中存储的问题了,这应该在C语言、计算机组成原理、数字电路等课程中不止一次的讲过。我们知道数字在计算机中是以二进制存储的。对于整数来说,只要不超过整数的表示范围,一定都可以表示成二进制的形式,比如8是100,9是101,88是1011000,可是小数小数部分就没有那么幸运了,根据二进制转换成十进制的规则(适当复习一下:把该小数不断乘2,再取所得的整数部份,直至没有小数为止)。
由于二进制中所有的小数存储的位数是有限,因此我们得知“任何十进制整数都可以精确转换成一个二进制整数,但任何十进制小数却不一定能精确转换成一个二进制小数,只要转换过程中乘积的小数部分满足所需精度即可”。比如对于0.1来说就不能精确转换为一个二进制小数,在16位小数的限制条件下,离它最近的二进制小数是0.0001100110011,也就是十进制的0.0999755859375。所以虽然你写程序的时候写的是0.1开始这个数存储到b这个float变量里的时候就变成了0.0001100110011,也就是0.0999755859375,因此你输出它的时候就会出现精度误差了,这种误差是不可避免的。
当然你可以指定“%f”的精度,比如:
float b=702.1;
printf("%.1f",b);
这时候就可以输出“702.1”了,但是这只是“恰巧输出正确而已”,因为“0.0999755859375”在转换为一位小数精度的时候“恰巧”能够四舍五入成0.1而已,并不是像我们想像的那样“解决误差问题”
原创粉丝点击