分析浮点数精度损失

2024年 3月 5日 59.7k 0

什么是精度损失?

精度损失指的是在数据存储中想要存储的的值与实际值不一致,比方说你想要存储在数据库存 123.456,但是存到数据库里就变成了 123.4560013。下图 a 字段的类型设置的是 float,当我们输入 123.456 并保存到数据库之后就变成了123.4560013,这就发生了精度损失。

为什么会发生精度损失?

计算机使用二进制存储数据,由于二进制自身局限性,导致其无法精确的表示所有小数,具体说就是计算机在将小数转换为二进制时,转换后的位数可能很长,超过了存储位数,这就就必须舍弃多余的位数,从而造成了实际值与存储值不一致,产生精度损失。

十进制转换为二进制

对于十进制整数转换为二进制,采用“除二取余,逆序排列”法,假设我们将 127 转换成二进制,具体过程如下:

十进制小数转换为二进制

那么十进制小数转换成二进制小数采用“乘二取整,顺序排列”法,假设我们将 0.625 转换成二进制数,具体过程如下:

但是 0.625 是一个特例,当我们用 0.1 用同样的算法去计算时,我们会发现 0.1 的二进制小数会出现无限循环的情况,在这种情况下计算机就无法使用二进制数精确地表示 0.1 了。

那为了解决这个问题,就有了 IEEE-754 规范,需要注意的是这个规范并没有解决小数无法精确表示的问题,只是提出了一种使用近似值表示小数的方式,并引入了精度的概念。

一个浮点数 a 由两个数 m 和 e 表示:分析浮点数精度损失-1,m 是尾数,e 是指数。

Float的存储结构举例

float 存储遵循 IEEE 754标准,只占 4 个字节,总共 32 位,叫作单精度浮点数,内存结构如下图所示:

符号位:0 表示正数,1 表示负数

指数位:共 8 位,存储时应加上 127

尾数位:共 23 位

我们以 13.625 为例转换出它的内存结构:

  • 采用“除二取余,逆序排列”法,将整数部分的13转换为二进制得:1101。
  • 采用“乘二取整,顺序排列”法,将小数部分的0.625转换为二进制得:0.101。
  • 合二为一得:1101.101。
  • 将小数点向左移动,使小数点前只有一位,且保证这位为1得:分析浮点数精度损失-2,尾数为:1.101101,指数为:3。
  • 将指数加上 127,变为 130,将 130 转换为二进制得:10000010,此时指数正好为 8 位,如果不足 8 位前面补 0。
  • 由于尾数 1.101101 前面固定为 1,存储时可以省略,得到尾数为 101101,不足 23 位,末尾补17 个 0 得:10110100000000000000000。
  • 按照格式:符号位 + 指数位 + 尾数位得:0 + 10000010 + 10110100000000000000000 = 01000001 01011010 00000000 00000000

我们再回过头来分析,因为我们规定了尾数的长度为 23 位,当我们的小数部分转换出现无限循环时,超过了尾数的长度,那就要舍弃,那剩余的二进制和原先的数就会不一致了。

相关文章

Oracle如何使用授予和撤销权限的语法和示例
Awesome Project: 探索 MatrixOrigin 云原生分布式数据库
下载丨66页PDF,云和恩墨技术通讯(2024年7月刊)
社区版oceanbase安装
Oracle 导出CSV工具-sqluldr2
ETL数据集成丨快速将MySQL数据迁移至Doris数据库

发布评论