单精度浮点类型float不能精确表示实数的原因

float在内存中的存储方式

由高地址到低地址(从左到右依次为):
符号位(第31位)指数(第30 ~ 23位)尾数(第22 ~ 0位)
float总共4个字节–32位:

  1. 符号位 (共1位)
    最左边的是符号位,0表示正数,1表示负数
  2. 指数 (共8位)
    指数部分,同样用二进制类表示指数
  3. 尾数(共23位)
    尾数就是由23位小数+1位组成(稍后解释)

关于尾数

尾数用来保存浮点数的有效数字,以8.25举例,8.25的二进制表示为:1000.01,
所以8.25的有效数字为1000.01,也就是说8,25的尾数为1000.01。如果以科学记数法来表示就是1.00001*(2ˆ3 ),所以指数是3,尾数是1.00001,。但是,存储在float内存结构中尾数部分的不是1.00001,而是00001,也就是说1和点是不存储的。因为IEEE觉得,既然我们大家都约定把小数点移动到第一个有效数字之后,那么也就默认小数点前面一定有且只有一个1,所以把这个1存起来也浪费,干脆就不要了,这就是为什么上面说尾数是23位+1位的原因。所以,在计算机中,float内存结构的尾数部分实际存储的是00001(后面添0补足23位),但是真正的尾数应该是这个数本身1.00001,一位也不丢。
其实尾数这个叫法,我认为是放在32位最低位,也就是它排在末尾,所以起了个名字叫尾数,这很容易和小数这个概念纠缠在一起。8.25转换成二进制并以科学记数法表示是1.00001*(2ˆ3 ),float里它的尾数就是1.00001,实际存储的是00001,这个数的小数部分是.01,小数部分和尾数没有半毛钱关系。个人认为,不如直接叫浮点数来的简单,因为这个地方本身就是在表示这个实数(注意,此处的实数是指以科学记数法表示的)。

float不能以二进制来精确表示浮点数的真正原因

先来看个例子:求0.9的二进制表示
小数转换成二进制表示的方法为:每次取小数部分与2相乘,取结果的整数部分,直到积为0,最后将取出的数由上而下正序排列

0.9 * 2 = 1.8 取1
0.8 * 2 = 1.6 取1
0.6 * 2 = 1.2 取1
0.2 * 2 = 0.4 取0
0.4 * 2 = 0.8 取0
0.8 * 2 = 1.6 取1
0.6 * 2 = 1.2 取1
… …

所以0.9的二进制表示为:111001100 无限循环
我们会发现再往下取它是无限循环的,永远也取不尽。要想让这个算法停止,那小数部分要正好是0.5或者0.25等等可以被0.5整除的小数。但是这样的结果可遇不可求。所以大部分时候,小数转换成二进制表示是一个无限循环的数。但是,float中存放浮点数本身的尾数部分只有23位,只能保存小数点后23位数,意味着排在小数点第23位以后的数将会被丢弃,这就导致了该浮点数不能被精确表示,

发布了40 篇原创文章 · 获赞 18 · 访问量 7587

猜你喜欢

转载自blog.csdn.net/weixin_44395686/article/details/98498306
今日推荐