首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何在PostgreSQL中进行级联舍入?

如何在PostgreSQL中进行级联舍入?
EN

Stack Overflow用户
提问于 2020-04-24 20:54:30
回答 1查看 95关注 0票数 1

Cascade rounding是一种在保留浮点数的和的同时对浮点数组进行舍入的算法。如何在PostgreSQL中实现此算法?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-04-24 22:21:49

您可以在plpgsql中实现this function

代码语言:javascript
运行
复制
create or replace function cascade_rounding(float[])
returns int[] immutable language plpgsql as $$
declare
    fp_total float = 0;
    int_total int = 0;
    fp_value float;
    int_value int;
    result int[];
begin
    foreach fp_value in array $1 loop
        int_value := round(fp_value + fp_total) - int_total;
        fp_total := fp_total + fp_value;
        int_total := int_total + int_value;
        result := result || int_value;
    end loop;
    return result;
end $$;

select cascade_rounding(array[1.1, 1.2, 1.4, 1.2, 1.3, 1.4, 1.4])

 cascade_rounding
------------------
 {1,1,2,1,1,2,1}
(1 row) 

Db<>fiddle.中尝试该函数

更新。您可以将函数应用于列。示例表:

代码语言:javascript
运行
复制
create table my_table(id serial primary key, float_number float);
insert into my_table (float_number) 
select unnest(array[1.1, 1.2, 1.4, 1.2, 1.3, 1.4, 1.4])

查询:

代码语言:javascript
运行
复制
select 
    unnest(array_agg(id order by id)) as id,
    unnest(array_agg(float_number order by id)) as float_number,
    unnest(cascade_rounding(array_agg(float_number order by id))) as int_number
from my_table;

然而,这并不是一个完美的解决方案。查询相当复杂,而且不是最优的。

在Postgres中,您可以创建一个自定义聚合,目的是将其用作窗口函数。这不是特别困难,但需要一些知识,请参阅文档中的User-Defined Aggregates

代码语言:javascript
运行
复制
create type cr_type as (int_value int, fp_total float, int_total int);

create or replace function cr_state(state cr_type, fp_value float)
returns cr_type language plpgsql as $$
begin
    state.int_value := round(fp_value + state.fp_total) - state.int_total;
    state.fp_total := state.fp_total + fp_value;
    state.int_total := state.int_total + state.int_value;
    return state;
end $$;

create or replace function cr_final(state cr_type)
returns int language plpgsql as $$
declare
begin
    return state.int_value;
end $$;

create aggregate cascade_rounding_window(float) (
    sfunc = cr_state,
    stype = cr_type,
    finalfunc = cr_final,
    initcond = '(0, 0, 0)'
);

使用聚合作为窗口函数:

代码语言:javascript
运行
复制
select 
    id, 
    float_number, 
    cascade_rounding_window(float_number) over (order by id) as int_number
from my_table;

 id | float_number | int_number
----+--------------+------------
  1 |          1.1 |          1
  2 |          1.2 |          1
  3 |          1.4 |          2
  4 |          1.2 |          1
  5 |          1.3 |          1
  6 |          1.4 |          2
  7 |          1.4 |          1
(7 rows)    

Db<>fiddle.

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61408845

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档