关于ROUND函数的舍入问题分析

概述

round函数相信大家都比较了解,可以返回离输入参数最近的整数。但是pg中round用法还是有区别的:

复制代码
postgres=# \df round
                                       List of functions
   Schema   | Name  | Result data type | Argument data types |  Type  | fencedmode | propackage
------------+-------+------------------+---------------------+--------+------------+------------
 pg_catalog | round | double precision | double precision    | normal | f          | f
 pg_catalog | round | numeric          | numeric             | normal | f          | f
 pg_catalog | round | numeric          | numeric, integer    | normal | f          | f
(3 rows)

通过函数定义可知,round函数支持两种类型的入参,如下:

1,round(double)

复制代码
语法:ROUND(double)
入参:浮点类型(近似值),FLOAT/DOUBLE
功能:将double类数值截去所有的小数部分,返回离输入参数最近的整数。

2,round(numeric , decimals)

复制代码
语法:ROUND(numeric[, decimals])
入参:定点类型(精确值),DECIMAL/NUMERIC
功能:decimals指明需保留小数点后面的位数,四舍五入返回截断后的值。若忽略decimals选项,则截去所有的小数部分,并四舍五入。

接着来说下区别

1,适用类型不同

java 复制代码
# 入参类型为浮点类型,不支持指定小数位,因为入参本身是近似值,小数位截断没有意义
postgres=# select round(1.234::float);
 round
-------
     1
(1 row)

# 入参类型为定点类型,可选指定小数位
postgres=# select round(1.234::numeric);
 round
-------
     1
(1 row)

postgres=# select round(1.234::numeric,2);
 round
-------
  1.23
(1 row)

2,舍入规则不同

java 复制代码
# 入参类型为浮点类型,截断时的原则为奇进偶不进
postgres=# select round(2.5::float),round(3.5::float);
 round | round
-------+-------
     2 |     4
(1 row)

# 入参类型为定点类型,截断时的原则四舍五入
postgres=# select round(2.5::numeric),round(3.5::numeric);
 round | round
-------+-------
     3 |     4
(1 row)

postgres=# select round(2.25::numeric,1),round(2.35::numeric,1);
 round | round
-------+-------
   2.3 |   2.4
(1 row)

原理(此处可参考PG源码):

round(numeric)舍入模式为四舍五入,这里不再展开说明。

round(double)内核调用rint函数,根据手册可知舍入模式受参数影响,默认是FE_TONEAREST,规则为四舍六入五凑偶,5前为奇数进位,5前为偶数舍去。

常量宏 解释
FE_DOWNWARD 向负无穷大舍入
FE_TONEAREST 向最接近可表示值舍入
FE_TOWARDZERO 向零舍入
FE_UPWARD 向正无穷大舍入

可以通过函数fegetround和fesetround查看和修改浮点数的舍入方向。

定义于头文件<fenv.h> 解释
int fesetround(int round); 试图建立等于参数 round 的浮点舍入方向,参数为浮点舍入宏之一
int fegetround(); 返回对应当前舍入方向的浮点舍入宏

小结

一般来讲我们无需过多关注round舍入情况,但对于一些业务敏感场景,有必要区分浮点数和定点数的使用,必要时可以通过指定传参类型来确保结果符合预期。

相关推荐
lhldsg6 小时前
全民健身解决方案小程序开发:从0到1的技术实战
java·数据库·需求分析
jason成都6 小时前
Spring WebFlux 适配达梦新方案|dm‑r2dbc:Netty 异步传输的实验性 R2DBC 驱动
java·后端·spring
泡海椒6 小时前
内置SPI函数库详解:JQuick-Java Builtin工具类实战用法
java·开发语言·python
辰烨chenye6 小时前
LeetCode Hot 100 题解 · 二分篇
java·算法·leetcode
小羊没烦恼!7 小时前
Hello Web API系列教程——Web API与国际化
java·服务器·前端·javascript·php
小荷才露尖尖角,早有蜻蜓立上头8 小时前
过滤器的4种创建方式
java
大圣编蚕8 小时前
Java ByteArrayInputStream 详解:从入门到实战
java·开发语言·算法
程序员阿明8 小时前
idea把插件啥的不默认放在C盘
java·ide·intellij-idea
linweidong9 小时前
中科闻歌Java面试题及参考答案
java·python·大模型·提示词·ai agent·mcp·rag原理
OpenAnolis小助手9 小时前
一句话看透 JVM,SysOM 诊断 Skill 新增 Java 应用诊断能力
java·开发语言·jvm·阿里云·操作系统控制台·sysom