概述
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舍入情况,但对于一些业务敏感场景,有必要区分浮点数和定点数的使用,必要时可以通过指定传参类型来确保结果符合预期。