Dua*_*nne 6 t-sql database sql-server relational-database
我正在寻找非常准确的除法结果。
该SQL返回以下结果:
SELECT (CAST(297282.26 AS DECIMAL(38, 30)) / CAST(495470.44 AS DECIMAL(38, 30))) AS ResultDecimal
Run Code Online (Sandbox Code Playgroud)
SELECT (CAST(297282.26 AS FLOAT) / CAST(495470.44 AS FLOAT)) AS ResultFloat
Run Code Online (Sandbox Code Playgroud)
这是WolframAlpha的准确结果:
http://www.wolframalpha.com/input/?i=297282.26%2F495470.44
我的印象是DECIMAL比FLOAT更准确:
“由于浮点数和实数数据类型的近似性质,当需要精确的数字行为时(例如,在金融应用程序中,涉及舍入的操作或相等性检查中),请不要使用这些数据类型。而应使用整数,十进制,金钱或小金钱数据类型。”
https://technet.microsoft.com/zh-CN/library/ms187912(v=sql.105).aspx
为什么FLOAT计算给我的结果比使用DECIMAL时更准确?
希望您已经明白,仅仅因为该FLOAT版本在小数点后显示了更多数字,并不一定意味着这些是真实的数字。这是关于精度,而不是准确度。
导致这种精度损失的是函数本身,而不是和数据类型CAST之间的差异。FLOATDECIMAL
为了证明这一点,请将您之前的结果与此结果进行比较:
SELECT 297282.26 / 495470.44 AS ResultNoCast
Run Code Online (Sandbox Code Playgroud)
在我的查询版本中,文字数字中小数点的存在告诉 SQL Server 将值视为DECIMAL数据类型,并具有由服务器确定的适当长度和精度。结果比您CAST明确地执行时更精确DECIMAL。
可以在该函数的官方文档中的截断和舍入结果CAST下找到隐藏的原因线索:
当您转换小数位不同的数据类型时,有时结果值会被截断,有时会被四舍五入。下表显示了该行为。
From | To | Behavior
numeric | numeric | Round
Run Code Online (Sandbox Code Playgroud)
因此,每个单独的文字值在传入时都被视为 a NUMERIC(与 相同DECIMAL),并且被强制转换为NUMERIC,这一事实会导致舍入。
稍微预测一下你的下一个问题,如果你想从NUMERIC/DECIMAL数据类型得到更精确的结果,你只需要告诉 SQL Server 计算的每个组成部分都更精确:
SELECT 297282.26000000 / 495470.44000000 AS ResultSuperPrecise
Run Code Online (Sandbox Code Playgroud)
这似乎(通过实验)是我能得到的最精确的结果:在分子或分母中添加或删除 0 都会使结果不太精确。我无法解释为什么会这样,因为结果只有小数点右边 23 位。
我发现使用以下方法时的最佳精度:
SELECT (CAST(297282.26 AS DECIMAL(15, 9)) / CAST(495470.44 AS DECIMAL(24, 2))) AS ResultDecimal
Run Code Online (Sandbox Code Playgroud)
这给出了结果
0.599999991926864496699338915153
我认为实际值(100位)是:
0.5999999919268644966993389151530412187657451370862810705720405842980259326873264124495499670979362562...
请记住 SQL Server 将除法的最大精度和小数位数定义为:
最大精度 = (p1 - s1 + s2) + MAX(6, s1 + p2 + 1) -- 最多 38
最大比例 = 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
| 归档时间: |
|
| 查看次数: |
3776 次 |
| 最近记录: |