PostgreSQL12中浮点数输出算法优化带来的小问题

最近碰到同事发来这样两个SQL,开发反馈输出的结果异常。

复制代码
bill=# select 0.1284*100::float;
      ?column?
--------------------
 12.839999999999998
(1 row)


bill=# select (0.1284*100)::float;
 float8
--------
  12.84
(1 row)

乍一看其实能看出明显的区别,由于::符号的优先级是高于*的,所以没加括号导致结果不同。但是对于第一个SQL输出的结果却很奇怪,为什么会输出这样一个数字?而且将0.1284改成0.1184也不会有问题,这就让人有点费解了。

复制代码
bill=# select 0.1184*100::float;
 ?column?
----------
    11.84
(1 row)

于是我在几个不同版本的pg实例中测试了下,发现pg12及以后的版本均有这种情况,于是看了下12的release notes,发现如下的更新

可以看到,在pg12中使用新的算法输出real和double precision值来提高性能。同时对于extra_float_digits这个参数也有原先默认的0改成了现在默认为1。关于这个参数的含义及用法之前我也有写过文章说明过,这里就不在阐述。

按照官方建议,可以将该参数设置为0与原先低版本保持一致。

复制代码
bill=# show extra_float_digits ;
 extra_float_digits
--------------------
 1
(1 row)


bill=# set extra_float_digits = 0;
SET
bill=#  select 0.1284*100::float;
 ?column?
----------
    12.84
(1 row)

那么还有最后一个问题,为什么前面会输出12.839999999999998这么一串数字呢?可以看到前面的说明中有提到,当extra_float_digits大于零时(现在是默认值),只输出保留精确二进制值所需的最小数字。

这个是什么意思呢,由于前面我们输出的是float类型,当extra_float_digits=1时最多保留17位,但是由于新的浮点数输出算法,只要二进制相同,那么只保留到能得到该二进制的最小位数即可。

换句话说,12.839999999999998和12.84的二进制值是一样的,大家可以计算下,都是1100.110101110000101001,也就是说对于该数而言,两者是相等的。从下面也可以验证。

复制代码
bill=# select 12.839999999999998::float;
 float8
--------
  12.84
(1 row)
相关推荐
数据库小组6 小时前
2026 年,MySQL 到 SelectDB 同步为何更关注实时、可观测与可校验?
数据库·mysql·数据库管理工具·数据同步·ninedata·selectdb·迁移工具
华科易迅6 小时前
MybatisPlus增删改查操作
android·java·数据库
Kethy__6 小时前
计算机中级-数据库系统工程师-计算机体系结构与存储系统
大数据·数据库·数据库系统工程师·计算机中级
SHoM SSER6 小时前
MySQL 数据库连接池爆满问题排查与解决
android·数据库·mysql
熬夜的咕噜猫7 小时前
MySQL备份与恢复
数据库·oracle
jnrjian7 小时前
recover database using backup controlfile until cancel 假recover,真一致
数据库·oracle
lifewange8 小时前
java连接Mysql数据库
java·数据库·mysql
大妮哟8 小时前
postgresql数据库日志量异常原因排查
数据库·postgresql·oracle
还是做不到嘛\.9 小时前
Dvwa靶场-SQL Injection (Blind)-基于sqlmap
数据库·sql·web安全
不写八个9 小时前
PHP教程004:php链接mysql数据库
数据库·mysql·php