Java浮点型数据探究--IEEE754标准

1. 背景

刚接触编程时,不管是C还是Java,涉及到浮点型计算与比较时,书上总说要小心精度带来的误差的问题,并且比较时一般不能直接用==比较,而是通过abs(a-b)<e的方式来实现比较。一直不知道误差出现的原因以及背后的原理,直到最近在学习计算机系统时,学到了浮点在计算机内的表示,才明白了点其中的原因。
这里先用一段代码引出浮点在计算时发生的问题,最后总结产生原因:
public class Test {
    public static void main(String[] args) {
        System.out.println(2.0-1.1);
}
}


输出的结果是:0.8999999999999999
并不是0.9,这是为什么呢?

2. 浮点在Java中二进制的表示

首先声明,Java使用的是IEEE754标准(用来规定浮点在计算机中二进制的表示格式),浮点数值如果不加f修饰默认是Double型,Float(单精度)是32位,Doule(双精度)是64位的。
单精度和双精度在存储中,分为三个部分:
  1. 符号位子(Sign):0代表正,1代表负;
  2. 指数位(Exponent):用于存储科学技术法中的指数数据;
  3. 尾数部分(Fraction):存储科学计数法后面的尾数部分;

这3个部分,在单精度和双精度数据所占的字节数是不同的,具体如下图:


32位 符号位:1 bit 指数位:8 bits 尾数部分: 23 bits Bias:127(2^7-1)

64位 符号位:1 bit 指数位:11 bits  尾数部分: 52 bits Bias:1023(2^10-1)

Bias是固有常量,之后将二进制转化为十进制的小数点会用到。

2.1 分类

在说将上面的二进制格式转换为十进制小数点前,需要将浮点型数据做个分类:(以32位为例)

S(1位)    E(8位)        M(23位)    N(32位)  
符           0                0            (-1)S*2-126*(0.M) 为规格化数(+/- 0.0)
              0               不等于0      (-1)S*2-126*(0.M)为非规格化数
号       1到254之间    不等于0    (-1)S*2E-127*(1.M) 为规格化数
              255           不等于0      NaN(非数值) 
位           255            0           无穷大

(1)其中NaN之间也可以是不等的,原因就是M部分的数值可以是不同的。
(2)浮点中是有0是有正负的,但它们的值是一样大的。
(3)第二类非规格化数可以扩大浮点型的大小范围,但转化方式要特别注意。java中的最小值就是这种类型,二进制位000......001,最后结果1.4E-45。
(4)java中任何正数/0为正无穷,任何负数/0为负无穷。 

2.2 二进制向十进制小数点转换

注意:此公式只适用于第三类规格化数。

转化公式:
(1)32位
=(-1)s×(1.)×2E-127     e-127(127就是Bias)
(2)64位
=(-1)s×(1.)×2E-1023    e-1023(1023就是Bias)
其中,s是符号位,M是尾数,E是阶码,e是实际的指数值
将S,M,E带入转化为十进制,最后计算的x结果,即是十进制的小数。

逆向转化:
ex:-3.75
(1) 首先转化为2进制表示(关键就是转化成2进制科学技术形式)
−3.75=−(2+1+1/2+1/4)=−1.111×2^1
(2) 整理符号位并进行规格化表示
−1.111×2^1=(−1)(1)×(1+0.1110 0000 0000 0000 0000 000)×2^1
(3) 进行阶码的移码处理
(−1)(1)×(1+0.1110 0000 0000 0000 0000 000)×2^1
=(−1)(1)×(1+0.1110 0000 0000 0000 0000 000)×2^(128−127)
于是,符号位S=1,尾数M为1110 0000 0000 0000 0000 000阶码E为128=1000 00002,则最终的32位单精度浮点数为1 1110 0000 0000 0000 0000 000 1000 0000

3. 总结

有了以上知识,就可以解释刚开始提出的问题了,其实答案很简单,对于一些小数,是没有完美的二进制与其对应的,只能取它尽可能近似的值,比如1.1,是无法完美转化成二进制的,所有就有了结果的误差。






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值