postgresql四舍五入下半函数

postgresql四舍五入下半函数,postgresql,floating-point,plpgsql,rounding,floating-accuracy,Postgresql,Floating Point,Plpgsql,Rounding,Floating Accuracy,PostgreSQL中的舍入(数值、整数)函数仅对以下各项进行取整: round(cast (41.0255 as numeric),3) ==> 41.026 由于我们需要一个返回41.025的圆函数,而且(令人惊讶的是)PostgreSQL中没有这样的函数(我们使用的是9.1.5),所以我们编写了一个“包装器”函数,它在第一个版本中非常简单和粗糙……但是我们没有找到更好的函数,因为在plpgsql中缺乏对此类问题的本机支持 代码如下所示。问题是它对于我们的目的来说太慢了。 你能建议一

PostgreSQL中的舍入(数值、整数)函数仅对以下各项进行取整:

round(cast (41.0255 as numeric),3) ==> 41.026
由于我们需要一个返回41.025的圆函数,而且(令人惊讶的是)PostgreSQL中没有这样的函数(我们使用的是9.1.5),所以我们编写了一个“包装器”函数,它在第一个版本中非常简单和粗糙……但是我们没有找到更好的函数,因为在plpgsql中缺乏对此类问题的本机支持

代码如下所示。问题是它对于我们的目的来说太慢了。 你能建议一个更好的方法来处理这项任务吗

代码如下:

    CREATE OR REPLACE FUNCTION round_half_down(numeric,integer) RETURNS numeric 
    AS $$
    DECLARE
      arg ALIAS FOR $1;
      rnd ALIAS FOR $2;
      tmp1 numeric;
      res numeric;
    BEGIN
      tmp1:=arg;
      IF cast(tmp1 as varchar) ~ '5$'  THEN res:=trunc(arg,rnd);
      ELSE res:=round(arg,rnd);
      END IF;

      RETURN res;
    END;
    $$ LANGUAGE plpgsql;
我需要转换数值并使用regexp…这就是(我想)破坏性能的原因

正如您所知:我们需要这样做,因为我们必须比较存储在两个不同列(在两个不同的表上)中但具有不同数值数据类型的数字:一个是double,一个是real。问题是,当插入到实际数据类型列中时,PostgreSQL执行向下取整,而它不通过其数学函数提供这样的选项

编辑:
这个函数实际上被窃听了。这是第一次快速重写,试图提高工作函数的性能,但速度非常慢

行为必须符合以下要求:
如果
舍入延迟的十进制数字是
trunc

其他
汇总

一些例子:

select round_half_down(cast (41.002555 as numeric),3) -- 41.002 
select round_half_down(cast (41.002555 as numeric),4) -- 41.0025 
select round_half_down(cast (41.002555 as numeric),5) -- 41.00255 
而PostgreSQL中的round函数提供:

select round(cast (41.002555 as numeric),3) -- 41.003
我们必须比较存储在两个不同列中的数字 (在两个不同的表上)但具有不同的数字数据类型:一个是 双和一是真实的

这应该非常快速和简单:

SELECT dp_col, real_col
FROM   tbl
WHERE  dp_col::real = real_col
基本上,只需将
双精度
数字转换为
实数
进行比较


如果这对您不起作用,则此SQL函数应能正常工作并更快地工作:

它还演示了@Parveen的函数和您编辑的版本是如何计算错误的-它们
trunc()
在不应该计算的地方。

创建或替换函数,将其向下舍入到小数点(数字、整数)
create or replace function round_down_to_decimal_places(numeric,integer)
returns numeric stable language sql as $$ 

select
case
when $1 >= 0 then
case when $1 - round($1, 3) < 0 then round($1, 3) - 0.001 else 
round($1, 3) end
else
case when $1 - round($1, 3) > 0 then round($1, 3) + 0.001 else 
round($1, 3) end
end

$$;
以$$形式返回数值稳定语言sql 选择 案例 当$1>=0时,则 当$1轮($1,3)<0时,则轮($1,3)-0.001其他 一轮($1,3)结束 其他的 当$1-轮($1,3)>0,则轮($1,3)+0.001其他 一轮($1,3)结束 结束 $$;
您可以通过更改(0.001表示3位小数,0.0001表示4位小数等)来使用泛型

由OP编辑: @帕维尔:我修改了你的函数,使它能以一种通用的方式工作

create or replace function round_half_down(numeric,integer)
returns numeric stable language sql as $$ 

select
case
when $1 >= 0 then
    case 
        when ($1 - round($1, $2)) < 0 then cast((round($1, $2) - (1.0/(10^$2))) as numeric) 
    else round($1, $2) end
else
    case 
        when ($1 - round($1, $2)) > 0 then cast((round($1, $2) + (1.0/(10^$2))) as numeric)
    else round($1, $2) end
end

$$;
创建或替换函数向下舍入(数值,整数)
以$$形式返回数值稳定语言sql
选择
案例
当$1>=0时,则
案例
当($1-轮($1,$2))<0时,将((轮($1,$2)-(1.0/(10^$2)))转换为数字)
其他回合(1美元,2美元)结束
其他的
案例
当($1-轮($1,$2))>0时,将((轮($1,$2)+(1.0/(10^$2)))转换为数字)
其他回合(1美元,2美元)结束
结束
$$;

试试这个希望可以帮助你这里有一个更简单的方法

CREATE OR REPLACE FUNCTION roundHalfDown(value NUMERIC, prec INTEGER)
RETURNS NUMERIC AS $$
BEGIN
  RETURN trunc(value * 10^prec + 0.5 - 0.000000001) / 10^prec;
END
$$ LANGUAGE 'plpgsql';

方法非常快速,无需创建新函数,新函数可以按如下方式进行四舍五入:

--凑齐一半

round($n, 3)
--四舍五入

round($n-0.5, 3)
很简单:

尝试使用这个函数

CREATE OR REPLACE FUNCTION ROUND_HALF_DOWN(NUMERIC)
  RETURNS NUMERIC LANGUAGE SQL AS
$FUNC$
  SELECT CASE WHEN ($1%1) < 0.6 THEN FLOOR($1) ELSE CEIL($1) END;
$FUNC$
创建或替换函数向下舍入(数值)
返回数值语言SQL作为
$FUNC$
当($1%1)<0.6时选择案例,然后选择楼层($1),否则CEIL($1)结束;
$FUNC$

您希望
-41.0255
四舍五入到
-41.025
还是
-41.026
?另外:您想将
41.02551
四舍五入到
41.025
还是
41.026
?您好,erwin brandstetter,函数实际上有错误。是第一次重写以提高工作函数的性能,但速度非常慢。行为必须符合以下条件:如果舍入延迟的十进制数字为trunc,则舍入。一些示例:选择round_half_down(强制转换(41.002555为数字),3--41.002选择round_half_down(强制转换(41.002555为数字),4--41.0025选择round_half_down(强制转换(41.002555为数字),5--41.00255,而postgresql中的round函数:选择round(强制转换(41.002555为数字),3--41.003I更新了我的答案以匹配您的更新。顺便说一句,这类信息应该进入你的问题,而不是难以阅读的评论。你的两个功能都计算错误。我在我的答案中添加了一个演示。@Erwin:事实上,第二个是我提出的Parveen函数的一个通用版本:)@BangTheBank:如果您有一些实质性不同的答案(如此处),最好添加您自己的答案。所以不要阻止回答你自己的问题。@ErwinBrandstetter,谢谢你指出这一点。我明白你的意思,但在这种情况下,我只是接受了帕文最初的想法,并试图将其概括。@BangTheBank:仍需大量编辑,应进入单独的答案。如果你做了编辑,你应该明确下半部分是你(BangTheBank)写的,而不是原作者(Parveen)。像“我已经修改了…”这样的文本只有在研究了编辑历史后才会变得清晰。不是应该的样子。@user500501:那么对
real
进行强制转换对您或函数有用吗?非常感谢您的回答。奇怪的是,演员阵容并不完美。我正在做更多的测试来找出原因,因为这听起来是我问题的正确(简单)答案。奇怪的是,它没有匹配它应该匹配的所有行,并且需要很长时间才能找到不匹配的行来发现问题。基本上,REAL列中的所有值都必须与DOUBLE-PRECISION列中的“casted to-REAL”值匹配(因为这只是在将值插入REAL列时发生的情况),但事实并非如此!4267717中的73761行不匹配。不适用于负值<代码>当$1%0.1^$2时的情况应该是
当ABS时的情况($1%0.1^$2)
@sufleR:抓得好。谢谢,现在修好了。这只适用于p后面没有数字的情况
round($n, 3)
round($n-0.5, 3)
CREATE OR REPLACE FUNCTION ROUND_HALF_DOWN(NUMERIC)
  RETURNS NUMERIC LANGUAGE SQL AS
$FUNC$
  SELECT CASE WHEN ($1%1) < 0.6 THEN FLOOR($1) ELSE CEIL($1) END;
$FUNC$