为什么 FLOAT 给我的结果比 DECIMAL 更准确?
Why does a FLOAT give me a more accurate result than a DECIMAL?
我正在寻找极其准确的除法结果。
这个SQLreturns结果如下:
SELECT (CAST(297282.26 AS DECIMAL(38, 30)) / CAST(495470.44 AS DECIMAL(38, 30))) AS ResultDecimal
SELECT (CAST(297282.26 AS FLOAT) / CAST(495470.44 AS FLOAT)) AS ResultFloat
这是 WolframAlpha 的准确结果:
http://www.wolframalpha.com/input/?i=297282.26%2F495470.44
我的印象是 DECIMAL 比 FLOAT 更准确:
"Because of the approximate nature of the float and real data types, do not use these data types when exact numeric behavior is required, such as in financial applications, in operations involving rounding, or in equality checks. Instead, use the integer, decimal, money, or smallmoney data types."
https://technet.microsoft.com/en-us/library/ms187912(v=sql.105).aspx
为什么 FLOAT 计算给我的结果比使用 DECIMAL 时更准确?
它没有给你更准确的结果。我这么说是因为该值是一个近似值,并非所有值都可用于存储在浮点数中。不过,硬币的另一面是 float 有可能更精确。 decimal/numeric 的最大精度为 38。https://msdn.microsoft.com/en-us/library/ms187746.aspx
当你查看 float 时,虽然最大精度是 53。https://msdn.microsoft.com/en-us/library/ms173773.aspx
希望您已经明白,仅仅因为 FLOAT
版本在小数点后显示更多数字,并不一定意味着这些是 true 数字。这是关于 精度,而不是 准确性。
是 CAST
函数本身导致了这种精度损失,而不是 FLOAT
和 DECIMAL
数据类型之间的差异。
为了证明这一点,请将您之前的结果与以下结果进行比较:
SELECT 297282.26 / 495470.44 AS ResultNoCast
在我的查询版本中,文字数字中存在小数点告诉 SQL 服务器将这些值视为 DECIMAL
数据类型,具有由服务器。结果比 CAST
显式 DECIMAL
.
更精确
可以在 CAST
函数的 official documentation 中找到对此原因的线索,在 截断和舍入结果 下:
When you convert data types that differ in decimal places, sometimes the result value is truncated and at other times it is rounded. The following table shows the behavior.
From | To | Behavior
numeric | numeric | Round
因此,每个单独的文字值在进入时都被视为 NUMERIC
(与 DECIMAL
相同),并被转换为 NUMERIC
,这导致四舍五入.
稍微预测一下你的下一个问题,如果你想从 NUMERIC
/DECIMAL
数据类型得到更精确的结果,你只需要告诉 SQL 服务器计算更精确:
SELECT 297282.26000000 / 495470.44000000 AS ResultSuperPrecise
这似乎(从实验中)是我能得到的最精确的:在分子或分母中添加或删除 0 会使结果不那么精确。我不知道为什么会这样,因为结果只有小数点右边 23 位。
好的,这就是我的想法。
@philosophicles - 我认为你是对的,因为 CAST 导致了问题,但不是因为我试图 "convert data types that differ in decimal places"。
当我执行下面的语句时
SELECT CAST((297282.26 / 495470.44) AS DECIMAL(38, 30)) AS ResultDecimal
计算的准确结果是
小数点后有 30 多位数字,我的数据类型的小数位数设置为 30。因此 CAST 对值进行四舍五入,然后在末尾添加零,直到有 30 位数字。我们最终得到这个:
所以有趣的是,CAST 如何确定要舍入或截断输出的小数位数?我不确定,但正如@philosophicles 指出的那样,输入的比例会影响对输出应用的舍入。
SELECT CAST(((297282.26/10000) / (495470.44/10000)) AS DECIMAL(38, 30)) AS ResultDecimal
想法?
也很有趣:
However, in simple terms, precision is lost when the input scales are
high because the result scales need to be dropped to 38 with a
matching precision drop.
https://dba.stackexchange.com/questions/41743/automatic-decimal-rounding-issue
The precision and scale of the numeric data types besides decimal are fixed.
https://dba.stackexchange.com/questions/41743/automatic-decimal-rounding-issue
我发现您使用时的精度最高:
SELECT (CAST(297282.26 AS DECIMAL(15, 9)) / CAST(495470.44 AS DECIMAL(24, 2))) AS ResultDecimal
这给出了
的结果
0.599999991926864496699338915153
我认为实际值(到 100 位)是:
0.5999999919268644966993389151530412187657451370862810705720405842980259326873264124495499670979362562...
请记住SQL服务器定义除法的最大精度和小数位数为:
max precision = (p1 - s1 + s2) + MAX(6, s1 + p2 + 1) -- up to 38
max scale = MAX(6, s1 + p2 + 1)
其中 p1 & p2 是两个数字的精度,s1 & s2 是数字的小数位数。
在这种情况下,最大精度为 (15-9+2) + MAX(6, 9+24+1) = 8 + 34 = 42。
但是SQL 服务器只允许最大精度为 38。
最大比例 = MAX(6, 9+24+1) = 34
我正在寻找极其准确的除法结果。
这个SQLreturns结果如下:
SELECT (CAST(297282.26 AS DECIMAL(38, 30)) / CAST(495470.44 AS DECIMAL(38, 30))) AS ResultDecimal
SELECT (CAST(297282.26 AS FLOAT) / CAST(495470.44 AS FLOAT)) AS ResultFloat
这是 WolframAlpha 的准确结果:
我的印象是 DECIMAL 比 FLOAT 更准确:
"Because of the approximate nature of the float and real data types, do not use these data types when exact numeric behavior is required, such as in financial applications, in operations involving rounding, or in equality checks. Instead, use the integer, decimal, money, or smallmoney data types."
https://technet.microsoft.com/en-us/library/ms187912(v=sql.105).aspx
为什么 FLOAT 计算给我的结果比使用 DECIMAL 时更准确?
它没有给你更准确的结果。我这么说是因为该值是一个近似值,并非所有值都可用于存储在浮点数中。不过,硬币的另一面是 float 有可能更精确。 decimal/numeric 的最大精度为 38。https://msdn.microsoft.com/en-us/library/ms187746.aspx
当你查看 float 时,虽然最大精度是 53。https://msdn.microsoft.com/en-us/library/ms173773.aspx
希望您已经明白,仅仅因为 FLOAT
版本在小数点后显示更多数字,并不一定意味着这些是 true 数字。这是关于 精度,而不是 准确性。
是 CAST
函数本身导致了这种精度损失,而不是 FLOAT
和 DECIMAL
数据类型之间的差异。
为了证明这一点,请将您之前的结果与以下结果进行比较:
SELECT 297282.26 / 495470.44 AS ResultNoCast
在我的查询版本中,文字数字中存在小数点告诉 SQL 服务器将这些值视为 DECIMAL
数据类型,具有由服务器。结果比 CAST
显式 DECIMAL
.
可以在 CAST
函数的 official documentation 中找到对此原因的线索,在 截断和舍入结果 下:
When you convert data types that differ in decimal places, sometimes the result value is truncated and at other times it is rounded. The following table shows the behavior.
From | To | Behavior
numeric | numeric | Round
因此,每个单独的文字值在进入时都被视为 NUMERIC
(与 DECIMAL
相同),并被转换为 NUMERIC
,这导致四舍五入.
稍微预测一下你的下一个问题,如果你想从 NUMERIC
/DECIMAL
数据类型得到更精确的结果,你只需要告诉 SQL 服务器计算更精确:
SELECT 297282.26000000 / 495470.44000000 AS ResultSuperPrecise
这似乎(从实验中)是我能得到的最精确的:在分子或分母中添加或删除 0 会使结果不那么精确。我不知道为什么会这样,因为结果只有小数点右边 23 位。
好的,这就是我的想法。
@philosophicles - 我认为你是对的,因为 CAST 导致了问题,但不是因为我试图 "convert data types that differ in decimal places"。
当我执行下面的语句时
SELECT CAST((297282.26 / 495470.44) AS DECIMAL(38, 30)) AS ResultDecimal
计算的准确结果是
小数点后有 30 多位数字,我的数据类型的小数位数设置为 30。因此 CAST 对值进行四舍五入,然后在末尾添加零,直到有 30 位数字。我们最终得到这个:
所以有趣的是,CAST 如何确定要舍入或截断输出的小数位数?我不确定,但正如@philosophicles 指出的那样,输入的比例会影响对输出应用的舍入。
SELECT CAST(((297282.26/10000) / (495470.44/10000)) AS DECIMAL(38, 30)) AS ResultDecimal
想法?
也很有趣:
However, in simple terms, precision is lost when the input scales are high because the result scales need to be dropped to 38 with a matching precision drop.
https://dba.stackexchange.com/questions/41743/automatic-decimal-rounding-issue
The precision and scale of the numeric data types besides decimal are fixed.
https://dba.stackexchange.com/questions/41743/automatic-decimal-rounding-issue
我发现您使用时的精度最高:
SELECT (CAST(297282.26 AS DECIMAL(15, 9)) / CAST(495470.44 AS DECIMAL(24, 2))) AS ResultDecimal
这给出了
的结果0.599999991926864496699338915153
我认为实际值(到 100 位)是:
0.5999999919268644966993389151530412187657451370862810705720405842980259326873264124495499670979362562...
请记住SQL服务器定义除法的最大精度和小数位数为:
max precision = (p1 - s1 + s2) + MAX(6, s1 + p2 + 1) -- up to 38
max scale = MAX(6, s1 + p2 + 1)
其中 p1 & p2 是两个数字的精度,s1 & s2 是数字的小数位数。
在这种情况下,最大精度为 (15-9+2) + MAX(6, 9+24+1) = 8 + 34 = 42。
但是SQL 服务器只允许最大精度为 38。
最大比例 = MAX(6, 9+24+1) = 34