分析浮点数精度损失

什么是精度损失?

精度损失指的是在数据存储中想要存储的的值与实际值不一致,比方说你想要存储在数据库存 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 表示:,m 是尾数,e 是指数。

Float的存储结构举例

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

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

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

尾数位:共 23 位

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

  • 采用"除二取余,逆序排列"法,将整数部分的13转换为二进制得:1101。
  • 采用"乘二取整,顺序排列"法,将小数部分的0.625转换为二进制得:0.101。
  • 合二为一得:1101.101。
  • 将小数点向左移动,使小数点前只有一位,且保证这位为1得:,尾数为: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 位,当我们的小数部分转换出现无限循环时,超过了尾数的长度,那就要舍弃,那剩余的二进制和原先的数就会不一致了。

相关推荐
toooooop86 小时前
MySQL source导入实战:踩坑记,phpMyAdmin 502、source导入巨慢问题解决
mysql
hasty8 小时前
Origin 校验不是身份认证:MySQL MCP Server 漏洞给 AI 平台的警告
数据库·mysql·安全
JavaPub-rodert11 小时前
Docker 安装 MySQL 完整教程:从零部署数据库,到生产环境持久化配置
数据库·mysql·docker
隔窗听雨眠11 小时前
MySQL整库迁移至KaiwuDB完全指南:从数据类型映射到生产切换的系统性实践
数据库·mysql
2301_322414280412 小时前
活力孕康复APP 47737- 原创(免费领源码+部署教程+开发环境)
java·vue.js·spring boot·mysql·微信小程序·idea·微信开发者工具
YIAN16 小时前
手撸社区后端:一套可落地的用户 - 文章 - 互动体系 MySQL 表设计与优化思路
后端·mysql
码农学院17 小时前
零售电商GEO踩坑复盘:把 MySQL 商品库自动映射成 Product Schema 的完整方案
人工智能·mysql·零售·geo
ShineWinsu19 小时前
对于MySQL:索引的解析
linux·数据库·mysql·面试·笔试·索引·海量数据
服务端相声演员1 天前
in子查询的执行可能被优化为连接查询
mysql
写后端的胖头鱼2 天前
【高频面试题】深分页问题
数据库·mysql·数据库优化·深分页