符点数为什么不能精确存储,比如0.2计算机是不能精确存储的
来源:互联网 发布:网络骑士流星 编辑:程序博客网 时间:2023/09/28 02:42
转自:http://blog.csdn.net/ispeller/article/details/7643348
C语言贴吧看到的:
首先,为了让代码清楚一点,把楼主耍小聪明的伎俩去掉:
程序运行的结果是执行了if (a != a) 语句块的内容。
a = a / a 没什么好奇怪的,关于执行的结果我开始是这么认为的:
a = a / a 完了之后a 的值是NaN,表示不是任何数(后来我发现,对于大多数环境来说,这个没有定死)。
NaN 的32 位精度储存是这样的:
符号位:可以为0 或者1
指数域:0xFF
尾数域:Non zero
而IEEE 754明确规定(摘自维基百科):
比较运算. IEEE754定义了特殊情况: -inf = -inf, inf = inf and x ≠ NaN for any x (including NaN).
这样NaN 自然不等于NaN。
我把这个问题放到了群里:
群里的楼兰君如是说,我又很相信楼兰君,就到处查了一下:
程序执行了if (a != 1) 语句块的内容,不是完全和我想的一样 NaN != NaN
因为计算机没法对浮点型数进行精确的储存,所以对不确定值浮点数使用 == 和 != 运算符都是根本性错误的。
比较一个不确定浮点数有一种办法,就是做减法之后和某一个足够小的值取绝对值做大小比较,如果小于该值,那么就可以认为两个浮点数是相等的。
例如
if (fabs (floatNumber1 - floatNumber2) < 0.0000001) {
/* other code */
}
为什么这里说“不确定的浮点数”呢?你可以运行下面的代码:
#include <stdio.h>intmain (void) { printf ("0.2+0.1-0.1"); if (0.2+0.1-0.1 < 0.2) { printf (" < "); } else if (0.2+0.1-0.1 > 0.2) { printf (" > "); } else { printf (" == "); } printf ("0.2"); getchar (); return 0;}
我在Windows 7 用gcc 编译的结果:
然后你再试试这段代码少年,只是修改了一些数值而已:
#include <stdio.h>intmain (void) { printf ("0.5+0.125-0.125"); if (0.5+0.125-0.125 < 0.5) { printf (" < "); } else if (0.5+0.125-0.125 > 0.5) { printf (" > "); } else { printf (" == "); } printf ("0.5"); getchar (); return 0;}
相同的环境,我的结果是:
为什么都是看起来相同的数值,两段程序的结果就是不一样呢?
我们日常使用的是十进制,而计算机内部使用了二进制,十进制用二进制表示的时候,向上取整是一个不可避免的问题,我们看到的0.1 和 0.2 实际上是被向上取整的结果,而0.125 和 0.5 则是确定的数值,不会向上取整,所以输出了等于。
让我们看看具体的情况:
一个浮点数 根据IEEE 754 标准,是如下图存放的(约定俗成右边为低位):
32位的情况:
64位的情况:
NND昨天晚上突然断网了,垃圾学校垃圾网络。
昨晚打了一晚上雷,真害怕我的本本被劈死,幸好学校的网络没有悲剧。
接着说,这里只说32位的:
符号位复位代表正,置位就是负。
指数域是用移码表示的,这里会有一个127的偏移量,例如指数是2,那么指数域的值就是127+2 = 129。指数是-1,指数域的值就是127-1 = 126。
尾数域全是小数点之后的数,但是默认省略了一个最高位的1,如果尾数位全是0,其实是 1 0 0 0 ... 0
下面用乘2取整把 0.125 换成浮点数表示:
A. 0.125 x 2 = 0.25,取整数部分0,小数部分为0.25
B. 0.25 x 2 = 0.5,取整数部分0,小数部分为0.5
C. 0.5 x 2 = 1.0,取整数部分1,小数部分为0,结束
D. 从第一位开始读数,直到最后一位,得出 0.5 的二进制是0.001b
这时候就可以按照上面的浮点数结构把0.0001b 写成浮点数了,这里有个重要的问题:0.5 写成二进制是确定的值,相应浮点数也是确定的。为什么这么说呢,你可以用上面的方法把 0.2 化成二进制格式,你会发现一个问题:小数部分无法取到0,算法无法停止,而浮点数的位是有限的,那么只能保存一个近似的数值。这里的方法和十进制的四舍五入差不多,这里是零舍一入。既然0.2 是有取整情况存在的,那么0.1 也必然是要取整的。0.5 只需要用脚趾头想一下就知道,这玩意是可以确定的。
第一个程序的两个浮点数全部都是无法确定的,只能给出近似值,而第二个程序的两个浮点数全部是可以确定的,当然会得到如图片所示的结果。
所以和楼兰说的一样,对不确定值的浮点数直接比较是否相等根本就是错误的。
当然不是说楼主的代码有问题,目前已知的环境, a /= a 的结果有两种:NaN == a 或者 0.0 == a,这都是可以直接比较的。
- 符点数为什么不能精确存储,比如0.2计算机是不能精确存储的
- 有些符点数不能精确存储,为什么
- 为什么浮点数不能精确表示?
- 关于java不能精确计算的问题
- java中的Double为什么不能精确处理数据
- C语言为什么不能精确表示浮点数
- Mysql float 非精确存储
- 0.1在计算机中不能被精确表示(浮点数的陷阱其实也是二进制下的陷阱?)
- float不能做精确比较的原因粗解
- 对 double 不能算出精确值问题的思考
- Graphics.MeasureString 不能获得精确宽度的问题
- 解决DreamWeaver代码视图中文不能精确选中的问题
- 为什么不能往Android的Application对象里存储数据
- 为什么不能往Android的Application对象里存储数据
- 为什么不能往Android的Application对象里存储数据
- 为什么不能往Android的Application对象里存储数据
- 为什么不能往Android的Application对象里存储数据
- 为什么不能往Android的Application对象里存储数据
- 四层负载均衡—LVS
- 六个快速寻找长尾关键字的方法
- 悲观锁和乐观锁
- ubuntu14.04 开启root登陆
- Hduoj1579【水题】
- 符点数为什么不能精确存储,比如0.2计算机是不能精确存储的
- hadoop2.x常用端口、定义方法及默认端口、hadoop1.X端口对比
- 数据结构之散列表冲突的解决方法
- Java-关于前台jsp向后台传值
- static的含义及用法(待补充)
- 设计模式之装饰模式(Decorator)
- Java实现图:邻接矩阵表示、深度优先搜索、广度优先搜索、无向图的最小生成树
- work summary(2)
- <context-param>与<init-param>的区别与作用