- 浏览: 887867 次
- 性别:
- 来自: 武汉
文章分类
最新评论
-
小宇宙_WZY:
膜拜一下大神,解决了我一个大问题,非常感谢 orz
【解惑】深入jar包:从jar包中读取资源文件 -
JKL852qaz:
感谢,遇到相同的问题!
【解惑】深入jar包:从jar包中读取资源文件 -
lgh1992314:
为什么java中调用final方法是用invokevirtua ...
【解惑】Java动态绑定机制的内幕 -
鲁曼1991:
说的都有道理,protected只能被同一级包的类所调用
【解惑】真正理解了protected的作用范围 -
鲁曼1991:
...
【总结】String in Java
问题提出:12.0f-11.9f=0.10000038,"减不尽"为什么?
现在我们就详细剖析一下浮点型运算为什么会造成精度丢失?
1、小数的二进制表示问题
首先我们要搞清楚下面两个问题:
(1) 十进制整数如何转化为二进制数
算法很简单。举个例子,11表示成二进制数:
11/2=5 余 1
5/2=2 余 1
2/2=1 余 0
1/2=0 余 1
0结束 11二进制表示为(从下往上):1011
这里提一点:只要遇到除以后的结果为0了就结束了,大家想一想,所有的整数除以2是不是一定能够最终得到0。换句话说,所有的整数转变为二进制数的算法会不会无限循环下去呢?绝对不会,整数永远可以用二进制精确表示 ,但小数就不一定了。
(2) 十进制小数如何转化为二进制数
算法是乘以2直到没有了小数为止。举个例子,0.9表示成二进制数
0.9*2=1.8 取整数部分 1
0.8(1.8的小数部分)*2=1.6 取整数部分 1
0.6*2=1.2 取整数部分 1
0.2*2=0.4 取整数部分 0
0.4*2=0.8 取整数部分 0
0.8*2=1.6 取整数部分 1
0.6*2=1.2 取整数部分 0
......... 0.9二进制表示为(从上往下): 1100100100100......
注意:上面的计算过程循环了,也就是说*2永远不可能消灭小数部分,这样算法将无限下去。很显然,小数的二进制表示有时是不可能精确的 。其实道理很简单,十进制系统中能不能准确表示出1/3呢?同样二进制系统也无法准确表示1/10。这也就解释了为什么浮点型减法出现了"减不尽"的精度丢失问题。
2、
float型在内存中的存储
众所周知、 Java 的float型在内存中占4个字节。float的32个二进制位结构如下
float内存存储结构
4bytes 31 30 29----23 22----0
表示 实数符号位 指数符号位 指数位 有效数位
其中符号位1表示正,0表示负。有效位数位24位,其中一位是实数符号位。
将一个float型转化为内存存储格式的步骤为:
(1)先将这个实数的绝对值化为二进制格式,注意实数的整数部分和小数部分的二进制方法在上面已经探讨过了。
(2)将这个二进制格式实数的小数点左移或右移n位,直到小数点移动到第一个有效数字的右边。
(3)从小数点右边第一位开始数出二十三位数字放入第22到第0位。
(4)如果实数是正的,则在第31位放入“0”,否则放入“1”。
(5)如果n 是左移得到的,说明指数是正的,第30位放入“1”。如果n是右移得到的或n=0,则第30位放入“0”。
(6)如果n是左移得到的,则将n减去1后化为二进制,并在左边加“0”补足七位,放入第29到第23位。如果n是右移得到的或n=0,则将n化为二进制后在左边加“0”补足七位,再各位求反,再放入第29到第23位。
举例说明: 11.9的内存存储格式
(1) 将11.9化为二进制后大约是" 1011. 1110011001100110011001100..."。
(2) 将小数点左移三位到第一个有效位右侧: "1. 011 11100110011001100110 "。 保证有效位数24位,右侧多余的截取(误差在这里产生了 )。
(3) 这已经有了二十四位有效数字,将最左边一位“1”去掉,得到“ 011 11100110011001100110 ”共23bit。将它放入float存储结构的第22到第0位。
(4) 因为11.9是正数,因此在第31位实数符号位放入“0”。
(5) 由于我们把小数点左移,因此在第30位指数符号位放入“1”。
(6) 因为我们是把小数点左移3位,因此将3减去1得2,化为二进制,并补足7位得到0000010,放入第29到第23位。
最后表示11.9为: 0 1 0000010 011 11100110011001100110
再举一个例子:0.2356的内存存储格式
(1)将0.2356化为二进制后大约是0.00111100010100000100100000。
(2)将小数点右移三位得到1.11100010100000100100000。
(3)从小数点右边数出二十三位有效数字,即11100010100000100100000放
入第22到第0位。
(4)由于0.2356是正的,所以在第31位放入“0”。
(5)由于我们把小数点右移了,所以在第30位放入“0”。
(6)因为小数点被右移了3位,所以将3化为二进制,在左边补“0”补足七
位,得到0000011,各位取反,得到1111100,放入第29到第23位。
最后表示0.2356为:0 0 1111100 11100010100000100100000
将一个内存存储的float二进制格式转化为十进制的步骤:
(1)将第22位到第0位的二进制数写出来,在最左边补一位“1”,得到二十四位有效数字。将小数点点在最左边那个“1”的右边。
(2)取出第29到第23位所表示的值n。当30位是“0”时将n各位求反。当30位是“1”时将n增1。
(3)将小数点左移n位(当30位是“0”时)或右移n位(当30位是“1”时),得到一个二进制表示的实数。
(4)将这个二进制实数化为十进制,并根据第31位是“0”还是“1”加上正号或负号即可。
3、浮点型的减法运算
浮点加减运算过程比定点运算过程复杂。完成浮点加减运算的操作过程大体分为四步:
(1) 0操作数的检查;
如果判断两个需要加减的浮点数有一个为0,即可得知运算结果而没有必要再进行有序的一些列操作。
(2) 比较阶码(指数位)大小并完成对阶;
两浮点数进行加减,首先要看两数的 指数位 是否相同,即小数点位置是否对齐。若两数 指数位 相同,表示小数点是对齐的,就可以进行尾数的加减运算。反之,若两数阶码不同,表示小数点位置没有对齐,此时必须使两数的阶码相同,这个过程叫做对阶 。
如何对 阶(假设两浮点数的指数位为 Ex 和 Ey ):
通过尾数的移位以改变
Ex
或
Ey
,使之相等。
由
于浮点表示的数多是规格化的,尾数左移会引起最高有位的丢失,造成很大误差;而尾数右移虽引起最低有效位的丢失,但造成的误差较小,因此,对阶操作规定
使尾数右移,尾数右移后使阶码作相应增加,其数值保持不变。很显然,一个增加后的阶码与另一个相等,所增加的阶码一定是小阶。因此在对阶时,总是使小阶向大阶看齐
,即小阶的尾数向右移位
(
相当于小数点左移
)
,每右移一位,其阶码加
1
,直到两数的阶码相等为止,右移的位数等于阶差
△
E
。
(3) 尾数(有效数位)进行加或减运算;
对阶完毕后就可
有效数位
求和。
不论是加法运算还是减法运算,都按加法进行操作,其方法与定点加减运算完全一样。
(4) 结果规格化并进行舍入处理。
略
浮点数的加减法:具体见http://www.zzslxx.com/wmy/jy/Chap02/2.7.1.htm
4、 计算12.0f-11.9f
12.0f 的内存存储格式为: 0 1 0000010 10000000000000000000000
11.9f 的内存存储格式为: 0 1 0000010 011 11100110011001100110
可见两数的指数位完全相同,只要对有效数位进行减法即可。
12.0f-11.9f 结果: 0 1 0000010 00000011001100110011010
将结果还原为十进制为: 0.000 11001100110011010= 0.10000038
评论
0 1 0000010 00000011001100110011010 ”希望您在看一下
发表评论
-
NIO
2010-08-05 10:36 0在JDK1.4以前,I/O输入输出处理,我们把它称为旧 ... -
【总结】Java线程同步机制深刻阐述
2010-05-16 10:21 5930全文转载:http://www.iteye ... -
【JDK优化】java.util.Arrays的排序研究
2010-05-12 21:06 9111作者题记:JDK中有很多算法具有优化的闪光点,值得好好研究。 ... -
【JDK优化】 Integer 自动打包机制的优化
2010-03-12 19:14 4077我们首先来看一段代码: Integer i=100; In ... -
【总结】Java与字符编码问题详谈
2009-12-30 09:11 9346一、字符集和字符编码方式 计算机只懂得0/1两种信号 ... -
【解惑】 正确理解线程等待和释放(wait/notify)
2009-12-29 13:40 19653对于初学者来说,下面这个例子是一个非常常见的错误。 /** ... -
【解惑】JVM如何理解Java泛型类
2009-12-16 11:08 12221//泛型代码 public class Pair<T& ... -
【解惑】正确的理解this 和 super
2009-12-05 09:46 4413转载: 《无聊 ... -
【解惑】真正理解了protected的作用范围
2009-11-21 18:00 4997一提到访问控 ... -
【总结】String in Java
2009-11-21 17:52 10806作者:每次上网冲杯Java时,都能看到关于String无休无止 ... -
【解惑】真正理解了protected的作用范围
2009-11-16 17:11 585一提到访问控制符protected,即使是初学者 ... -
总结Java标准类库中类型相互转化的方法
2009-11-09 21:57 210组一: ☆ String → byte[ ... -
方法没覆盖住带来的烦恼
2009-11-05 09:18 100Object类是所有类的祖宗,它的equals方法比较的 ... -
【解惑】数组向上转型的陷阱
2009-11-03 11:44 1836问题提出: 有两个类Manager和Em ... -
【总结】java命令解析以及编译器,虚拟机如何定位类
2009-11-01 16:25 5744学Java有些日子了,一直都使用IDE来写程序。这 ... -
【解惑】领略内部类的“内部”
2009-10-19 15:38 3535内部类有两种情况: (1) 在类中定义一个类(私有内部类 ... -
【解惑】深入jar包:从jar包中读取资源文件
2009-10-08 21:13 65413我们常常在代码中读取一些资源文件(比如图片,音乐,文 ... -
【解惑】理解java枚举类型
2009-09-26 09:37 3352枚举类型是JDK5.0的新特征。Sun引进了一个全新的关键字e ... -
编写自己的equals方法
2009-09-20 14:18 129在我的《令人头疼的"相等"关 ... -
【解惑】Java类型间的转型
2009-09-11 16:03 5589★ 基本数据类型间的转换 1、Java要做到平台无关 ...
相关推荐
java解惑java解惑java解惑java解惑java解惑java解惑
Java解惑Java解惑Java解惑Java解惑Java解惑Java解惑Java解惑Java解惑Java解惑Java解惑Java解惑Java解惑
高中化学必修1模块培训中问题解惑分析.doc
JAVA解惑,你面包括一些java经典的问题。
解惑SQL
java解惑,深入剖析java深入剖析java
Java解惑.pdf Java解惑.pdf Java解惑.pdf Java解惑.pdf
《Java解惑》《Java解惑》《Java解惑》《Java解惑》《Java解惑》《Java解惑》
JAVA解惑.pdf JAVA解惑.pdf JAVA解惑.pdf
SQL解惑(第2版)
Java解惑中文版 Java解惑 java健壮程序
JAVA解惑和易错知识解析 ,吐血奉献!
EXCEL函数公式解惑专集EXCEL函数公式解惑专集
扫描完整版 解惑大数据 解惑大数据 解惑大数据 解惑大数据
这是一本关于即将进入IT界的大学生,写的一本书,用来解惑职场将出现的问题
IT 学生解惑经典指导书 IT 学生解惑经典指导书 IT 学生解惑经典指导书 IT 学生解惑经典指导书 IT 学生解惑经典指导书 IT 学生解惑经典指导书 IT 学生解惑经典指导书 IT 学生解惑经典指导书
C语言解惑中文版.pdf 扫描版
IT学生解惑真经
IT 学生解惑真经