添加四舍五入的小数百分比等于 1(或 100%)
Posted
技术标签:
【中文标题】添加四舍五入的小数百分比等于 1(或 100%)【英文标题】:Adding rounded decimal percentages to equal 1 (or 100%) 【发布时间】:2020-07-31 20:48:49 【问题描述】:在这种情况下,我需要计算一系列数字余额的百分比,四舍五入到小数点后 10 位,但它们的总和必须为 1.0000000000(或 100.0000000000%)。我可以得到 0.9999999998 或 1.0000000004,但我似乎无法达到 1.0。还有什么我可以做的吗?
create table balances (balance number);
insert into balances (balance) select 27544020.38 from dual;
insert into balances (balance) select 3161670.46 from dual;
insert into balances (balance) select 13085937.87 from dual;
insert into balances (balance) select 0 from dual;
insert into balances (balance) select 0 from dual;
insert into balances (balance) select 478033.04 from dual;
insert into balances (balance) select -85126.17 from dual;
insert into balances (balance) select 44968439.88 from dual;
insert into balances (balance) select 78155926.33 from dual;
insert into balances (balance) select -3662788.36 from dual;
insert into balances (balance) select 234328177.96 from dual;
insert into balances (balance) select 103694040.23 from dual;
insert into balances (balance) select 85295156.11 from dual;
insert into balances (balance) select 155627180.9 from dual;
insert into balances (balance) select 133311464.77 from dual;
insert into balances (balance) select 56306616.42 from dual;
insert into balances (balance) select 135204546.73 from dual;
insert into balances (balance) select 188572856.42 from dual;
insert into balances (balance) select 118208964.69 from dual;
insert into balances (balance) select 87751901.55 from dual;
insert into balances (balance) select 947 from dual;
insert into balances (balance) select 61190729.16 from dual;
insert into balances (balance) select 35307571.39 from dual;
insert into balances (balance) select 32229181.69 from dual;
insert into balances (balance) select 27544020.38 from dual;
insert into balances (balance) select 3161670.46 from dual;
insert into balances (balance) select 13085937.87 from dual;
我正在计算这组余额的百分比:
ratio_to_report(balance) over ()
并将其四舍五入到小数点后 10 位:
round(ratio_to_report(balance) over (), 10)
当我运行如下查询时:
select balance, ratio_to_report(balance) over (), round(ratio_to_report(balance) over (), 10) as pctg
from balances;
这个结果看起来不错,但是当我通过以下方式检查 sum(pctg) 时:
select sum(pctg) from
(
select balance,
ratio_to_report(balance) over (),
round(ratio_to_report(balance) over (), 10) pctg
from balances
)
我明白了:
SUM(PCTG)
------------------
1.0000000004
在添加四舍五入到小数点后 10 位的小数百分比时,是否有其他技术或函数始终得到 1.0000000000 的总和?
【问题讨论】:
这很简单。如果你想得到精确的 1.0,那么不要总结四舍五入的值。 好像和***.com/q/9161404/2527905类似 【参考方案1】:没有完美的解决方法。从本质上讲,四舍五入确实会影响全局计算,之后您可以做的任何事情都只是围绕基本的数学规则工作。
想到的一项棘手的工作是计算四舍五入值的运行总和,并调整其中一个值以使总数匹配;例如,我们可以调整最大的pctg
(因为它可能不太明显)。这并不干净,在极端情况下可能会产生违反直觉甚至错误的结果。
看起来像:
select
rtr,
pctg,
case when row_number() over(order by pctg desc) = 1
then 1 - sum(pctg) over(order by pctg) - pctg
else pctg
end adujsted_ptcg
from (
select
balance,
ratio_to_report(balance) over () rtr,
round(ratio_to_report(balance) over (), 10) pctg
from balances
) t
order by pctg desc
当然,还有其他替代方案(例如计算整体不匹配,然后尝试在多组行之间或多或少地平均分配) - 但它们中的任何一个都不是干净的。
【讨论】:
“它们都不是干净的”取决于“干净”的定义。例如,考虑以下优化问题:为每个百分比分配一个带有 10 个精确小数位的“有趣的四舍五入”小数。在“四舍五入”百分比的总和 = 1 的情况下,最小化“错误”的平方和。我相信这是一个完全有效的、“干净”的问题陈述,并且它有一个简单的 SQL 解决方案。示例:如果数字是 1/3、1/3、1/3(并且假设只有三个精确的小数),则该过程将返回 0.333、0.334、0.333。解决方案并不总是唯一的,但确实存在。【参考方案2】:这是一种方式 - 它在某种意义上是“最佳的”(“最佳”的具体意义是不平凡的,也许不是特别相关)。
with
prep (balance, rn, p_sum) as (
select balance, rownum,
sum(balance) over (order by rownum) / sum(balance) over ()
from balances
)
select balance,
round(p_sum, 10) - round(lag(p_sum, 1, 0) over (order by rn), 10)
as percentage
from prep
;
这个想法是跟踪百分比的非四舍五入累积总和;然后将这些累积总和四舍五入;然后将连续四舍五入的累积和的差值作为百分比的“四舍五入值”。
“最佳方式” - 只是不要要求数学证明:如果您考虑所有“四舍五入”百分比的分配,每个非四舍五入的百分比最多十位小数,并且总和必须完全相等1,然后你计算“错误”的平方和(这个有趣的四舍五入的百分比减去确切的百分比),我在这个查询中实现的策略将最小化这个错误的平方和。
这也可以用ratio_to_report
编写,但由于我也无法在同一个查询中对其进行分析求和,因此我更喜欢直接计算“报告比率”。
【讨论】:
【参考方案3】:如果我没记错的话,问题出在值被除法所破坏。示例:三行,每行的值为 10。每行代表总数的 1000/3% 或 33.‾3%。 (对不起,我还没有找到一种方法来让 vinculum 超过它所属的三个。)如果你将它四舍五入到任意位数,你最终得到的总和小于原始总数。例如。 33.3 + 33.3 + 33.3 = 99.9,而 33.‾3 + 33.‾3+ 33.‾3 = 100.
因此,您不能将单个百分比四舍五入到 n 位,但仍然保证得到 100。您必须要么自愿伪造一些数字,要么显示分数。
【讨论】:
以上是关于添加四舍五入的小数百分比等于 1(或 100%)的主要内容,如果未能解决你的问题,请参考以下文章