java

今天和文龙,法兵讨论float的在计算机中的表示的时候发现我们对其中的一些不是很了解,经过讨论和分析最后终于明白了具体的细节

我们知道计算机中有两种基本的浮点形式:
1:单精度浮点数:占用32,在java中:float
2:双精度浮点数:占用64位,在java中:double

下面是IEEEE单精度浮点数:
符号位 指数位 尾数位
1(31) 8(23-30) 23(0-22)
(博客)
 0:22 位包含 23 位小数 f,其中第 0 位是小数的最低有效位,第 22 位是最高有效位。
IEEE 标准要求浮点数必须是规范的。这意味着尾数的小数点左侧必须为 1,因此我们在保存尾数的时候,可以省略小数点前面这个 1,从而腾出一个二进制位来保存更多的尾数。这样我们实际上用 23 位长的尾数域表达了 24 位的尾数。
 23:30 位包含 8 位偏置指数 e,第 23 位是偏置指数的最低有效位,第 30 位是最高有效位。
8 位的指数为可以表达 0 到 255 之间的 256 个指数值。但是,指数可以为正数,也可以为负数。为了处理负指数的情况,实际的指数值按要求需要加上一个偏差(Bias)值作为保存在指数域中的值,单精度数的偏差值为 127;偏差的引入使得对于单精度数,实际可以表达的指数值的范围就变成 -127 到 128 之间(包含两端)。在本文中,最小指数和最大指数分别用 emin 和 emax 来表达。稍后将介绍实际的指数值 -127(保存为全0)以及 +128(保存为全 1)保留用作特殊值的处理。
 最高的第 31 位包含符号位s。s为0表示数值为正数,而s为1则表示负数。

9.625为例,
我们转化为二进制格式:1001.101,这个时候计算机会对其进行移位操作,并用指数形式表示
其规范浮点数表达为 1.001101 × 23
按照上面的IEEE的表示方法表示的话可以这样转化:
1, 符号位:由于他是正数,所以符号位为0;
2, 指数位:由于他的指数是23即表示左移了3位,这里要加上一个偏移值127,即130,转化成八位二进制为,1000 0010
3, 尾数位:这里尾数位是1.001101,但是在保存的时候,根据规范小数点左侧必须为1,所以保存的时候可以腾出一个二进制位,所以实际保存的时候是:
0011 0100 0000 0000 0000 000
因此按单精度格式表示为:
0 10000010 00110100000000000000000

这就是在计算机中实际的表示,但是如果我们来手动通过二进制来转换为十进制的话会出现一些问题:
下面就是我们开始的时候计算的方法:
1.符号位是0,所以直接去掉,剩下 10000010 00110100000000000000000
2 指数位转化为十进制130,然后减去偏移值127,得出指数位是3,所以应该是小数位*23
3 我们算出小数位00110100000000000000000的十进制的值(这里我们是直接拉到windows的计算器里进行计算的,所以得出的结果是0.1703936)
4 然后用小数位0.1703936*23 = 1.3631
这时候我们发现算出的结果和原数据相差太大,太坑爹了。这个时候发现我们在把小数位的二进制转化为十进制的时候没有加1
所以算出的小数位应该是1.1703936,这个时候我们用1.1703936*23=9.36314,
但是这个时候算出的结果和原数据也是有偏差的,这个时候我们在想,难道是因为计算机把数据截取了还是windows的计算器不给力。


最后经过一番思考过后,文龙发现了问题,他发现我们对指数位还原为十进制后应该对小数位右移指数位的值,比如:这里算出的指数位的值是3,这样我们就对小数位+1进行右移,
即:1.00110100000000000000000,进行右移3位,右移后为:100.110100000000000000000,这个时候我们把他转化为十进制,这个时候就没问题了,完全还原成了原数据。


后来思考,发现主要的问题在于在二进制和十进制转化时候的移位和小数点前加1两个点上。所以二进制转化为十进制的时候应该首先对二进制进行移位,之后转化成时间值,而不是先把小数位转化为十进制,再乘以指数位。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值