一尘不染

SQL Server:十进制精度/小数位数产生奇怪的结果

sql

我正在为一个项目处理一些SQL,但是我注意到在SQL Server中一些看似奇怪的行为,即用小数除法得到的答案是什么样的。

以下是一些示例,这些示例说明了我所看到的行为:

DECLARE @Ratio Decimal(38,16)
SET @Ratio = CAST(210 as Decimal(38,16))/CAST(222 as Decimal(38,16));

select @Ratio -- Results in 0.9459450000000000

DECLARE @Ratio Decimal(38,16)
SET @Ratio = CAST(210 as Decimal)/CAST(222 as Decimal);

select @Ratio -- Results in 0.9459459459459459

对于上面的代码,(似乎)不太精确的查询答案给出了更精确的值作为答案。当我同时将被除数和除数都设置为时Decimal(38,16),我得到一个小数位数为6的数字(将其转换为a会Decimal(38,16)导致0填充小数位数)。

当我将除数和除数仅转换为默认的十进制,而没有手动设置精度或小数位数时,我得到的结果小数位数全为16位。

出于好奇,我开始使用以下查询对它进行更多的实验:

select CAST(210 as Decimal(38,16))/CAST(222 as Decimal(38,16)) --0.945945
select CAST(210 as Decimal(28,16))/CAST(222 as Decimal(28,16)) --0.9459459459
select CAST(210 as Decimal(29,16))/CAST(222 as Decimal(29,16)) --0.945945945

如您所见,随着我提高精度,答案的规模似乎减小了。我看不到结果的规模与被除数和除数的规模或精度之间的相关性。

我发现了一些其他问题,这些问题指向msdn文档中的某个位置,该位置指出通过对除数和除数的精度和小数位数进行一组计算,可以确定对小数进行运算时得到的精度和小数位数,并且:

结果精度和小数位的绝对最大值为38。当结果精度大于38时,相应的小数位会减小,以防止结果的整数部分被截断。

因此,我自己尝试遍历这些方程式,以确定将aDecimal(38,16)分解为另一个的Decimal(38,16)结果,根据我的发现,我仍然应该获得比我更精确的数字。

所以我做错了数学,或者这是我所缺少的其他事情。非常感谢您提供的任何见解。

提前致谢…


阅读 160

收藏
2021-05-30

共1个答案

一尘不染

关于价值的奥秘以及何时应用该函数,文档尚不完整,但这是基于该文档的调查结果表。6``max

如其所言,除法公式为:

结果精度= p1-s1 + s2 + max(6,s1 + p2 + 1) ,结果标度= max(6,s1 + p2 + 1)

并且,正如您自己突出显示的那样,我们将添加脚注:

结果精度和小数位的绝对最大值为38。当结果精度大于38时,相应的小数位会减小,以防止结果的整数部分被截断。

因此,这是我在电子表格中生成的内容:

p1 s1 p2 s2 prInit srInit prOver prAdjusted srAdjusted
38 16 38 16 93     55     55     38         6
28 16 28 16 73     45     35     38         10
29 16 29 16 75     46     37     38         9

因此,我正在使用prsr指示结果的精度和小数位数。该prInitsrInit的公式是完全从文档的forumlas。我们可以看到,在所有3种情况下,结果的精度都远远大于38,因此脚注适用。prOver只是max(0,prInit - 38)-如果脚注适用,我们必须调整多少精度。prAdjusted就是prInit - prOver。在这三种情况下,我们都可以看到结果的最终精度为38

如果我申请了 相同的
调整因子,去鳞,那么我会得到的结果0109。但是我们可以看到,您针对该(38,16)案例的结果的等级为6。因此,我认为那是max(6,...文档部分实际适用的地方。所以我的最终公式srAdjustedmax(6,srInit-prOver),现在我的最终Adjusted值似乎与您的结果匹配。


而且,当然,如果我们参考的文档decimal,我们可以看到 默认
精度和小数位数(如果您未指定的话)为(18,0),因此这是未指定精度和小数位数的行:

p1 s1 p2 s2 prInit srInit prOver prAdjusted srAdjusted
18 0  18 0  37     19     0      37         19
2021-05-30