你懂浮点数吗?你知道浮点数计算机是怎么表示的吗?让我们一起来聊聊浮点数的前世今生

浮点数在java的八大数据类型中占据了两个位子float和double。我们一接触java就会了解他们,但是很少有人真正去了解过浮点数,是怎么实现的,为什么叫浮点数。
我们先来看一个案例:

public static void main(String[] args) {
        double ans=0;
        for (int i = 0; i < 100; i++) {
            ans+=0.1;
        }
        System.out.println(ans);
    }

执行的结果:
在这里插入图片描述
可能有的人会想了,这我知道啊浮点数底层有误差,计算结果可能不精确,老师讲浮点数的时候就讲过这个案例呀,确实大家都是知道的。
那我们再看一个案例:

 public static void main(String[] args) {
        double ans=0;
        for (int i = 0; i < 100; i++) {
            ans+=0.5;
        }
        System.out.println(ans);
    }

执行的结果:
在这里插入图片描述
这里就有疑问了,为什么0.1加100次有误差,0.5加100却没有误差。
是不是疑惑了?疑惑就说明打开这边文章你是会有收获的,接下来我们看看是为什么吧。
首先我们从字面开始:浮点数。
浮点数并不是计算机中特有的名词。我们先来看一个数字:1.234。
他还有几种表示形式:
在这里插入图片描述
这种可以将小数点进行左右移动的数字就叫做浮点数(小数点的浮动)。所以我们表示一个浮点数需要多少信息?
就拿上图中的第一个为例:
1.我们需要知道最前面乘的数字0.1234,我们把它叫做尾数
2.我们需要知道最后指数函数的基底是什么,即图中的10,我们把它叫做基数
3.我们需要知道是10的几次方,即图中的1,我们把它叫做指数
4.最后的最后(其实这个应该放在第一个的),我们当然需要知道他是正数还是负数,我们把它叫做符号
所以浮点数的符号表达式就是下图:
图片来自《程序是怎样跑起来的》
由于计算机底层使用的是二进制,所以我们需要使用二进制的表示形式。但是小数形式怎么表示为浮点数的二进制呢?
比如我们现在有一个十进制数123.456,那么该数中的每一个都是有他对应的指数。那么我们可以顺推到二进制
在这里插入图片描述
我们现在来想一想1.75怎么用二进制来表示呢?
在这里插入图片描述
就如图中的类比,1.75在二进制中的表示方式就是1.11。
但是问题又来了,这只是书面的表示形式,计算机底层又是怎么表示的呢?
还记得上图3.3中的浮点数四大要素:符号,尾数,基数,指数。由于我们使用的是二进制的表示形式,所以基数其实已经是确定为2的。我们只需要有一个数据结构能够记录符号,尾数,指数即可。
符号位最为简单,只需要保留第一位:0表示正数,1表示负数即可。这时候我们就只剩下尾数和指数了。
浮点数有多种表示形式:
在这里插入图片描述
为了方便计算机的统一管理,需要制定统一的规则。就好比我们之前学过的科学计数法一样,制定一个统一的规范。这个规范就是将小数点前面的值固定为1的正则表达式,通过小数点的左移和右移来实现。举个例子:
在这里插入图片描述
因为这个规定所以我们只要记录小数点后的数据就可以了(第一位肯定是一个1),我们就可以表示更多的数据了。
这样我们的尾数和指数就已经确定了,只剩下怎么表示的问题。尾数很简单,他本来就是一个二进制数直接保存就可以了。
指数是一个十进制的数,所以我们只需要把它转为二进制即可。但是你在将他转换为二进制的时候发现他有正负号的区别,难道又要在指数上再引入一个符号位吗?这是十分麻烦的,所以我们在这儿引入EXCESS系统。
EXCESS系统很简单,比如你现在有一个区间[-10,10],那么你可以找一个同等长度的区间[0,20],再将这两个区间一一映射
0表示-10
10表示0
20表示10
这样通过正区间[0,20]就可以表示含负数的区间[-10,10]。综合上述的所有,浮点数的构思就完成了,现在就是具体的实现环节。
浮点数的表示方式有很多,我们这里使用最为普遍的IEEE(美国电气和电子工程师协会)标准。
图片来自《程序是怎样跑起来的》
我们这里就用单精度浮点型(float)来举例。
具体案例就使用0.75.单精度浮点型共有32位,其中1位为符号位,8位表示指数部分,23位表示尾数部分。因为float使用了8位来表示指数,8位二进制表示的范围是0-255.所以我们根据EXCESS系统记127为0.如需表示-1,底层记录的数据为0111 1110(126)。
在这里插入图片描述
根据图中我们知道0.75使用二进制表示时,符号为正,尾数为1.1,指数为-1,这样根据上面的推导我们就可以列出各个部分的表达式。
在这里插入图片描述
就可以列出0.75的表达式
0-0111 1110-1000 0000 0000 0000 000。
回顾到一开始的问题中,为什么0.1会有误差呢?
我们试着将0.1使用二进制的方式表示。
可以发现在进行书面表示的时候就会陷入无限的循环之中。
0.00011001100110011
根本无法准确的表示出来,所以在表示0.1时,只能将其截取。所以0.1在底层表示为0-0111 1011-100 1100 1100 1100 1100 1101(接下来是1所以需要有一个进位。0舍1入)。这也是为什么0.1累加会有误差的原因。而0.5很轻松的就可以表示为二进制(0.1)所以不会有误差。
大佬们点个赞再走呀!!!
大佬们点个赞再走呀!!!
大佬们点个赞再走呀!!!
在这里插入图片描述

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值