为什么FLOAT给我的结果比DECIMAL更准确?

时间:2015-10-30 13:12:07

标签: sql-server database tsql relational-database

我正在寻找一个非常准确的除法结果。

此SQL返回以下结果:

SELECT (CAST(297282.26  AS DECIMAL(38, 30)) / CAST(495470.44 AS DECIMAL(38, 30))) AS ResultDecimal

enter image description here

SELECT (CAST(297282.26 AS FLOAT) / CAST(495470.44 AS FLOAT)) AS ResultFloat

enter image description here

以下是WolframAlpha的准确结果: enter image description here http://www.wolframalpha.com/input/?i=297282.26%2F495470.44

我的印象是DECIMAL比FLOAT更准确:

“由于float和实际数据类型的近似性质,当需要精确的数字行为时,不要使用这些数据类型,例如在财务应用程序,涉及舍入的操作或相等检查中。 ,使用整数,小数,金钱或小数据数据类型。“

https://technet.microsoft.com/en-us/library/ms187912(v=sql.105).aspx

为什么FLOAT计算比使用DECIMAL时更准确?

4 个答案:

答案 0 :(得分:2)

我发现你使用时的最佳精确度是:

SELECT (CAST(297282.26  AS DECIMAL(15, 9)) / CAST(495470.44 AS DECIMAL(24, 2))) AS ResultDecimal

这给出了

的结果
  

0.599999991926864496699338915153

我认为实际值(到100位)是:

  

... 0.5999999919268644966993389151530412187657451370862810705720405842980259326873264124495499670979362562

请记住,SQL Server将划分的最大精度和比例定义为:

  

最大精度=(p1 - s1 + s2)+ MAX(6,s1 + p2 + 1) - 最多38

     

max scale = MAX(6,s1 + p2 + 1)

p1& p2是两个数字的精度,s1& s2是数字的比例。

在这种情况下,最大精度为(15-9 + 2)+ MAX(6,9 + 24 + 1)= 8 + 34 = 42.

但是,SQL Server仅允许最大精度为38。

最大比例= MAX(6,9 + 24 + 1)= 34

答案 1 :(得分:1)

它没有为您提供更准确的结果。我这样说是因为该值是近似值,并非所有值都可用于存储在浮点数中。在那个硬币的另一边,浮子有可能更精确。小数/数字的最大精度为38. https://msdn.microsoft.com/en-us/library/ms187746.aspx

当您查看浮点数时,最大精度为53. https://msdn.microsoft.com/en-us/library/ms173773.aspx

答案 2 :(得分:1)

希望您已经明白,仅仅因为FLOAT版本在小数点后面显示更多数字,并不一定意味着那些是真正的数字。这是关于精度,而不是准确度

CAST函数本身导致精度损失,而不是FLOATDECIMAL数据类型之间的差异。

为了证明这一点,请将您之前的结果与以下结果进行比较:

SELECT 297282.26  / 495470.44  AS ResultNoCast

Result without using CAST function

在我的查询版本中,文字数字中存在小数点表示SQL Server将值视为DECIMAL数据类型,具有服务器确定的适当长度和精度。结果比CAST明确DECIMAL时更精确。

隐藏在CAST函数的official documentation隐藏在截断和舍入结果下的

  

转换小数位数不同的数据类型时,有时会截断结果值,有时会舍入结果值。下表显示了该行为。

From     | To       | Behavior
numeric  | numeric  | Round

因此,在进入NUMERIC的过程中,每个单独的文字值被视为DECIMAL(与NUMERIC相同)的事实会导致舍入。

稍微预测下一个问题,如果您想从NUMERIC / DECIMAL数据类型获得更精确的结果,您只需告诉SQL Server计算的每个组成部分都更精确:< / p>

SELECT 297282.26000000  / 495470.44000000  AS ResultSuperPrecise

enter image description here

这看起来(来自实验)是我能得到的最精确的:从分子或分母中添加或删除0会使结果不那么精确。我无法解释为什么会这样,因为结果只是小数点右边的23位数。

答案 3 :(得分:0)

好的,这就是我的想法。

@philosophicles - 我认为你是正确的,因为CAST导致问题,但不是因为我试图转换小数位不同的数据类型&#34;。

当我执行以下声明时

SELECT CAST((297282.26 / 495470.44) AS DECIMAL(38, 30)) AS ResultDecimal

计算的准确结果是

enter image description here

小数点后面的位数超过30位,我的数据类型的比例设置为30.因此CAST对值进行舍入,然后只将末尾添加零,直到有30位数。我们最终得到了这个:

enter image description here

有趣的是,CAST如何确定要舍入或截断输出的小数位数?我不确定,但正如@philosophicles指出的那样,输入的比例会影响输出的舍入。

SELECT CAST(((297282.26/10000) / (495470.44/10000)) AS DECIMAL(38, 30)) AS ResultDecimal

enter image description here

思想?

同样有趣:

  

但是,简单来说,输入音阶时精度会丢失   因为结果比例需要降低到38   匹配精度下降。

https://dba.stackexchange.com/questions/41743/automatic-decimal-rounding-issue

  

除十进制之外的数值数据类型的精度和比例是固定的。

https://dba.stackexchange.com/questions/41743/automatic-decimal-rounding-issue