简体   繁体   English

SQL 服务器:避免舍入错误

[英]SQL Server: Avoiding Rounding Errors

I need help with floating-point Maths in SQL Server.我需要 SQL 服务器中的浮点数学方面的帮助。 Simplified version of the problem is given below下面给出了问题的简化版本

DECLARE @TOTALCOST NUMERIC(18, 4) = 1.125;

WITH CTE AS (
    SELECT item='Item1', volume=3.636
    UNION
    SELECT item='Item2', volume=14.946
    UNION
    SELECT item='Item3', volume=26.05
)
SELECT
    item,
    volume,
    totVol = (SUM(volume) OVER (PARTITION BY NULL)),
    proportion =  (SUM(volume) OVER (PARTITION BY item)) / (SUM(volume) OVER (PARTITION BY NULL)),
    costAllocation = (SUM(volume) OVER (PARTITION BY item)) * @TOTALCOST / (SUM(volume) OVER (PARTITION BY NULL))
FROM CTE
ITEM    Volume  totVol  Proportion  costAllocation
==========================================
Item1   3.636   44.632  0.081466    0.091649
Item2   14.946  44.632  0.334871    0.376730
Item3   26.050  44.632  0.583661    0.656619

Basically proportion is ratio of item1 volume to total volume of three items, and then 1.125 is divided in that ratio.基本上比例是 item1 体积与三个 item 总体积的比率,然后 1.125 除以该比率。 That is for item1 proportion = 3.636 / 44.632 cost allocation = 3.636 * 1.125 / 44.632即对于 item1 比例 = 3.636 / 44.632 成本分配 = 3.636 * 1.125 / 44.632

What I want is round proportion and costAllocation to only 3 decimal places, but they exactly add upto 1 and 1.125 respectively.我想要的是将比例和成本分配四舍五入到小数点后三位,但它们恰好分别加起来为 1 和 1.125。

I have tried putting Round() function in various permutations but somehow, I am not able to exactly figure how to divide in proportion so that it exactly adds up to 1, and 1.125.我曾尝试将 Round() function 置于各种排列中,但不知何故,我无法准确计算出如何按比例划分,以便它恰好加起来等于 1 和 1.125。 I don't mind if there is an error in the last decimal place of one numbers.我不介意一个数字的最后一位小数是否有错误。 For example 1 can be divided equally in 3 parts = 0.333___ each, so even if we use regular round function to 3 places it will still show up as 0.333, and sum it 3 times will only be 0.999例如1可以平均分成3份=每份0.333___,所以即使我们用普通的round function到3个地方它仍然会显示为0.333,并且3次加起来只会是0.999

So I am ok with reporting the proportion as 0.333, 0.333, and 0.334 so that it adds up to exactly 1.所以我可以将比例报告为 0.333、0.333 和 0.334,这样它加起来正好是 1。

What you are dealing with is not floating point mathematics but just lack of decimal precision due to rounding.您要处理的不是浮点数学,而是由于四舍五入而缺乏小数精度。

A solution I've implemented (mainly in reporting) is to do something like the below, where you calculate the difference due to rounding and add that to one row (usually the largest value to minimise the effect).我已经实施的解决方案(主要是在报告中)是执行类似下面的操作,在其中计算由于四舍五入而产生的差异并将其添加到一行(通常是最大值以最小化影响)。

declare @TOTALCOST numeric(18, 4) = 1.125;

with CTE as (
    select item='Item1', volume=3.636
    union
    select item='Item2', volume=14.946
    union
    select item='Item3', volume=26.05
), cte2 as (
select
    item,
    volume,
    totVol = (Sum(volume) over ()),
    proportion =  Round((Sum(volume) over (partition by item)) / (Sum(volume) over ()),3),
    costAllocation = Round((Sum(volume) over (partition by item)) * @TOTALCOST / (Sum(volume) over ()),3),
    Row_Number() over(order by volume desc) rn
from CTE
)
select item, volume, totVol, proportion, 
    costAllocation + case when rn=1 then @TOTALCOST-Sum(costAllocation) over() else 0 end costAllocation
from cte2

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM