小数为什么有误差?
2012-11-07 13:11
253 查看
#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而已,并不是像我们想像的那样“解决误差问题”
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而已,并不是像我们想像的那样“解决误差问题”
相关文章推荐
- 小数在计算机中为什么会有误差?说明机器数、码制、浮点数、以及数制转换的一些问题
- 根本理解计算机中的小数为什么有误差
- 小数为什么有误差?
- 浮点运算结果为什么会出现误差
- js 小数计算误差
- 计算机程序的思维逻辑 - 小数计算为什么会出错?
- excel中小数为四位数,我把它设为二位数后,点这个栏为什么会在输入栏中仍然显示为四位小数呢?
- js 小数计算误差
- 在C语言中除法运算为什么没有小数部分?
- 为什么浮点数一定是有误差的
- C语言计算浮点数的小数位数,屏蔽掉了浮点运算的误差
- 为什么神经网络使用互熵而不是分类误差
- 在C语言中除法运算为什么没有小数部分?
- 计算机程序的思维逻辑 (5) - 小数计算为什么会出错?
- JAVA为什么有时候除法计算结果本来应该是小数。但是得到整数int类型
- 【转】为什么0.1无法被二进制小数精确表示?
- 为什么0.1无法被二进制小数精确表示?
- 快速解决小数运算误差问题
- JAVA的小数处理(避免默认的科学计数法造成的误差)
- hibernate的Criteria在数据库中求和,float格式求和为什么只有一位小数?