浮点数存储机制和int转float精度损失问题

之前几篇文章都是讲的正数的存储和加减乘除和位移运算,我被勾起了好奇心又去研究了一下浮点数,发现浮点数和正数的存储方式完全不一样,同时也证明了以前学习的粗陋.
我相信在刚学java的时候,一定会背这样一个规律:
int转为float可能损失精度,
int转为double不损失精度.
以前我学到这里的时候,死记硬背,不求甚解,回头再仔细看看,就有些看不懂了,int和float都是32位,为什么可能会损失精度,而转为double就没问题.
还有float的精度是7位或8位,double的精度是15位,为什么?怎么得出来的,还有这些位数是小数后的位数,还是所有的位数?
首先我们来了解一下浮点数这个概念,
浮点数之所以叫浮点数,就是因为它的小数点是不固定的,
它的表示方式是 基数X指数n.如103.12可以表示为1.0312x102或者0.10312x103,这就是小数点位置不确定,就是浮点数,所以同样可以用来表示正数,如100=1X102,这也是一个浮点数,所以平时程序里,我们把100改成100.0的时候,虽然他的值没变,但是它的存储方式改变了.
通过上面的例子,我们也知道一个数,可以转变为不同格式的浮点数,于是就有了各种不同的规定,而java的浮点数则是遵从于IEEE 754
在这里插入图片描述
上面的图就是float存储格式的示意图,第一位s是符号位,如果是0表示整个数是正数,如果是1则是负数, 后面8位阶码,表示指数
在计算机的世界里,进位都是二进制的,指数表示的也是2的N次幂
而剩下的23位就是表示底数,实际上它可以表示23位数字,因为IEEE 754规定:底数>=1且底数<2,所以底数的第一位是1(除了0,也分±0,除了符号位不同,其他位都为0,而1是二的0次方),所以干脆就把第一位省略掉,只记录小数点后面的数字.那么问题来了,1.0是二的0次方,它的小数点没有数字,唯一的一位数个位1被省略了,那么1的所有位数也应该是0,这不是和0相冲突码?
这里就要提出的是指数表示和以前表示方法不一样,它没有符号位,并不是指数没有负数, 而是采用了偏移量来表示 ,公式为
实际指数 =阶码-漂移量
指数的漂移量是127,阶码共有8位,所以它的表示范围就是-127~128.
这样表示1.0时,指数是127:00111111 10000000 00000000 00000000
所以我们可以得出float的范围就是
最大值:01111111 11111111 11111111 11111111=2129-2-23
到 0000000 00000000 00000000 00000001=2-23

最小值:11111111 11111111 11111111 11111111=-2129-2-23
到 1000000 00000000 00000000 00000001=-2-23
加上几个特殊值
无穷大:01111111 10000000 00000000 00000000
负无穷:11111111 10000000 00000000 00000000
0 :0000000 00000000 00000000 00000000
-0:1000000 00000000 00000000 00000000

这里我们就可以回答开始的几个问题了,
int转为float为什么可能损失精度,因为flout的基数只能表示二进制24位数,而int则是32位数,所以虽然flout表示的范围大很多,但是只要有效数字超过24位就会被舍弃,这就损失了精度.而224=16 777 216,八位数多一点,float的精度就是可以保证7位数和8位数的一小部分.
double和float一样的原理:只是它的阶码是11位,基数是52位,基数比int的32位大,当然可以完全表示,不会损失精度,如果是long值就不一定了,如果long值位置大于52位的时候,也可能损失精度.

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值