int转float精度丢失的问题解析 ( 浮点数的二进制存储方式, IEEE 754标准)

今天的学习中遇到了 int型数据转换成float型精度丢失的问题,

明明float的表示范围更大怎么会丢失精度呢?

问题深究下来就关系到了浮点数的存储方式, 这里复习下计算机组成的课本内容, 也给不知道的朋友学习下

编程中用到的浮点数就是float和double, 长度分别是32位和64位,

浮点数是以二进制的 小数乘指数的方式存储的, 底数是2 不是10

以32位的float举例: 

 十进制的0.65625转换为二进制浮点数:

  1. 先换成二进制小数:0.10101(数部分用除2取余的方法, 小数部分用乘2取整的方法)
  2. 移位, 移到小数点前只剩1. :   1.0101*2^(-1)   ( IEEE 754标准规定小数点前只留一位且是1,除非这个数是0这个过程叫规格化)
  3. 补全位数,1位符号位, 8位指数移码 ,23位尾数:
  • 先说第一部分符号位,正数为0,  所以第一位是 0
  • 尾数, 此例中就是1.0101,因为IEEE 754标准规定小数点前留1(为的是一个数的唯一表示,且防止全是0浪费位数),所以既然都是1.XXX就没必要存储这个1.了 ,直接存储小数点后的数即 0101, 补全23位也就是00000000000000000000101
  • 剩下 指数部分了,  指数用移码表示, 即加上偏移量 ,对于32位的float偏移量是127(二进制01111111), 64位double偏移量1023(二进制001111111111),此例中就是 (-1)+01111111=01111110

  把上边3部分连起来就得到了32位浮点数:00111111000000000000000000000101

学到这新同学们应该思考一下应该怎么把一个浮点数的2进制存储换回10进制数,就是上边过程的逆向

 上边的例子是 32位的浮点数,64位的浮点数的分布如下: 1位符号位, 11位指数移码(偏移量1023),尾数52位,方法和上边是一样的

还有一些特殊的值如下表,  S表示符号位,E表示加偏移量之前的指数,M表示去1.之前的尾数

学习到这里 , 我当时心里是有疑虑的, 指数为什么要加偏移量?多麻烦

大家可以查阅一些资料, 有时间可能会单写一个博客介绍为什么指数用移码表示

回到开篇的问题, 

int型数据转换成float型精度丢失的问题, 明明float的表示范围更大怎么会丢失精度呢?

 由上边的浮点数存储方式可以看出,32位浮点数有23位来拓展精度, int型整数4个字节,31位(1位符号位)全部用来拓展精度, 当int表示的数超过float所能表示的精度时, 只能靠丢失精度来近似表示了

说到这肯定还有很多人不理解,我们再以10进制举个简单的例子 ,

比如我定义8位十进制无符号的浮点数 , 4位表示指数,四位表示尾数,统一用0.XXX来格式化尾数,不存储0.

8位的整数全部表示十进制数

如果我把整数00001234化成浮点数即0.1234*10^4 = 0004|1234 (这里|分隔开指数和尾数)

那么我的整数如果是12345678呢, 按规则转化成浮点数是 0.12345678*10^8

按照我的规定,指数0008没问题,但是尾数却超出了4位,只能丢失一部分尾数来近似表达

也就是这样的8位浮点数虽然表示范围最大可以达到0.9999*10^(9999)  ,但是却不一定能精确表示比这个值小的一个整数

二进制的道理是一样的, 当int的值大于2 ^(24)    (或小于-2 ^(24)  )时, (请大家自己想一下为什么临界值是2 ^(24),结合尾数位)转换成float就有可能发生精度的丢失.

注意上边的话,大于或小于临界值时转换有可能造成精度的丢失, 为什么是有可能?

回顾我自定义的10进制 浮点数的例子,  

00123456无法用我定义的8位浮点数表示,  显然超过了我定义数的临界值

那么比这个数大的08000000呢?

不就是0008*10^(7)吗?位数补全就是0007|0008,

完全可以,没有精度丢失,而且离最大值差远了!

这又是为什么呢, 因为限制位数的浮点数能表示范围之内的数, 超过临界值是跳跃的,不能覆盖所有的整数(更别说实数了)

所以超过临界值 后就有可能无法精准表示范围内的整数,  这也就是int型数据转换成float型精度丢失的原因, 而转换成double就不会出现这个问题,因为double的尾数很长,  临界值比int最大值还要大,不可能造成精度丢失

大家明白了吗?慎用float, 尤其是关于钱的程序(好像对于金融领域double也不够)

因为水平有限,计算和概念可能出问题,欢迎沟通!

如有错误, 请大家及时指正,谢谢!

猜你喜欢

转载自blog.csdn.net/q5706503/article/details/82859504