根本理解计算机中的小数为什么有误差
2009-06-16 12:48
260 查看
beckle在如鹏论坛上提问:
#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而已,并不是像我们想像的那样“解决误差问题”
本文来自 “ 如鹏网”学生提问交流实况
#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而已,并不是像我们想像的那样“解决误差问题”
本文来自 “ 如鹏网”学生提问交流实况
相关文章推荐
- 小数在计算机中为什么会有误差?说明机器数、码制、浮点数、以及数制转换的一些问题
- 计算机整数为什么如此进行编码的一个更易理解的说明.值得学习.
- 深入理解计算机系统系列--[转] 计算机为什么用补码
- 【转载】计算机程序的思维逻辑 (5) - 小数计算为什么会出错?
- 深入理解计算机系统(序章)------谈程序员为什么要懂底层计算机结构
- 计算机程序的思维逻辑 - 小数计算为什么会出错?
- 小数为什么有误差?
- 深入理解计算机系统(序章)------谈程序员为什么要懂底层计算机结构
- 以C程序角度探究计算机里int 类型的存储与最大数最小数,为什么负数补码存储
- 计算机程序的思维逻辑 (5) - 小数计算为什么会出错?
- 计算机程序的思维逻辑 (5) - 小数计算为什么会出错?
- 深入理解计算机系统(2.7)------二进制小数和IEEE浮点标准
- 小数为什么有误差?
- 深入理解计算机系统(2.7)------二进制小数和IEEE浮点标准
- 为什么学到现在任然对计算机浑然不知???门外汉??? 对其运行机制不能理解?
- 计算机程序的思维逻辑 (5) - 小数计算为什么会出错?
- 误差与最大似然估计的个人理解
- 为什么车企纷纷招聘计算机安全专家
- 深入理解计算机系统--信息的表示和处理
- 32位和64位的区别--深入理解计算机系统笔记一