SQL Server:十进制精度/比例正在产生奇怪的结果

时间:2014-08-13 22:12:37

标签: sql sql-server sql-server-2012

我正在为一个项目研究一些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的数字(将其转换为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文档中某个位置的其他SO问题,这些问题表明在小数运算期间产生的精度和比例是通过对除数和被除数的精度和等级进行一组计算来确定的,那个:

  

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

所以我尝试自己运行这些方程,以确定将Decimal(38,16)划分为另一个Decimal(38,16)的输出看起来是什么样的,根据我发现的结果,我仍然应该得到更多比我确切的数字。

所以我要么做错了数学,要么就是在这里发生了一些我不知道的事情。我非常感谢任何人提供的任何见解。

提前致谢...

1 个答案:

答案 0 :(得分:4)

documentation关于值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公式正是文档中的论坛。我们可以看到,在所有3种情况下,结果的精度远远大于38,因此脚注适用。 prOver只是max(0,prInit - 38) - 如果脚注适用,我们需要调整精度。 prAdjusted只是prInit - prOver。我们可以在所有三种情况下看到结果的最终精度为38

如果我将相同的调整因子应用于比例,那么我将获得0109的结果。但我们可以看到(38,16)案例的结果的缩放比例为6。所以我认为这是文档的max(6,...部分实际应用的地方。因此,srAdjusted的最终公式为max(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