对于浮点数的理解

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ocp114/article/details/82779417

都知道像整型(int)数据直接转为二进制就可以保存了,但是带有小数的数据呢?小数点放在哪?用什么表示小数点?精确到第几位?确实一开始在好几年前工业设计会有很多这样的问题,大家规范又不统一,难免会产生混乱以及规格不统一带来的种种问题,但是后来出了 IEEE 754 标准,浮点数统一的问题基本解决了,所以下面讲解的也就是这个标准的实现方式。

这里以 32 位单精度浮点数(float)来阐述,至于双精度浮点数(double)在文末会作介绍。

1、表示方式:

例如 -5.23
11000000101001110101110000101000
如果按照普通二进制的方法来计算的话,上面的值就是 -1084709928,明显不对
那么请看下图

IEEE 754
上图中:
第 31 位最高位是符号位,这个不用说了
第 30 — 23 位是指数位(没错,就是表示 XXX 的多少次方的指数,后面解释怎么用)
第 22 — 0 位是尾数位(没错,就是这个浮点数的尾数,也就是小数点后面的值,但是是 -5.23 处理过后的值的小数部分)

那么,再来讲讲 -5.23 怎么得到 11000000101001110101110000101000 这个值
第 31 位:-5.23 是负数,所以为 1
第 30 — 23 位:

  1. 需要先从 -5.23 下手,由 -5.23 = -1.3075 * 2^2 得到指数 2(至于这里为什么会得到 -5.23 = -1.3075 * 2^2 这种操作,应该就是 IEEE 754 标准里面的吧,没有看过 IEEE 754,不太清除)
  2. 由于次方数也有分正负,所以第 30 — 23 位也需要区分正负,30 — 23 位的值是 0 — 255,所以 IEEE 754 就规定 0 — 127 为负次方,128 — 255 为正次方,由于上面计算得到的次方数是 2 ,为正次方,所以第 30 — 23 位的值是 127 + 2 = 129,用二进制表示就是 10000001 啦

第 22 — 0 位:
     这里是尾数位,由 -5.23 = -1.3075 * 2^2 得到小数部分尾数为 0.3075, 这里的需要对 0.3075 进行二进制表示,那么怎么得到这个二进制的值呢?其实和普通整型数据计算二进制的方式差不多,看下面就明白
在这里插入图片描述
代码实现方式:

public static void getMantissa(float value) {
    // 计算 23 次的原因是尾数只有 23 个
    for (int i = 0; i < 23; i++) {
        float temp = value * 2;
        if (temp > 1) {
            value = temp - 1;
            System.out.print(1);
        }else {
            value = temp;
            System.out.print(0);
        }
    }
}

至此,就完成了从一个十进制的小数浮点数到二进制的转换,
对于双精度浮点数(64位):第 63 位符号位,第 62 — 52 位表示指数位,第 51 — 0 位表示尾数位,计算方法类似

那么,二进制的浮点数转十进制的问题
从上面得到了 11000000101001110101110000101000 这个二进制的值

第 31 位 符号位 1 表示负数
第 30 — 23 位 10000001 = 129 得到 2 ^(129 - 127)= 4
第 22 — 0 位 01001110101110000101000:计算 0*2^-1 + 1*2^-2 + 0*2^-3 ……得到 0.30749988555908203125 哇!很神奇,上面的 0.3075 变成 0.30749988555908203125 了,所以浮点数精度丢失的原因就在这里
另外,如果指数位如果不全为 0 的话,0.30749988555908203125 需要加 1,否则不加,所以变成了 1.30749988555908203125
最后 综上所述:- 4 * 1.30749988555908203125 ≈ -5

猜你喜欢

转载自blog.csdn.net/ocp114/article/details/82779417