Hei*_*nzi 7 language-agnostic sql-server floating-point rounding
我们坚持使用一个数据库(不幸的是)使用浮点数而不是十进制值.这使得四舍五入有点困难.请考虑以下示例(SQL Server T-SQL):
SELECT ROUND(6.925e0, 2) --> returns 6.92
Run Code Online (Sandbox Code Playgroud)
ROUND
确实轮半起来,但由于浮点数不能准确地表示十进制数,"错误"的结果(从视终端用户的点)被显示.我理解为什么会这样.
我已经提出了两个可能的解决方案(两个都返回一个浮点数,不幸的是,这也是一个要求):
SELECT CONVERT(float, ROUND(CONVERT(decimal(29,14), 6.925e0), 2))
SELECT ROUND(6.925e0 * 1000, -1) / 1000
我应该选择哪一个?有更好的解决方案吗?(遗憾的是,由于某些遗留应用程序访问同一个数据库,我们无法更改数据库中的字段类型.)
是否存在针对此(常见?)问题的完善的最佳实践解决方案?
(显然,常规技术"四舍五入"在这里没有用,因为6.925已经四舍五入到小数点后三位 - 只要这可以在浮点数中.)
你的第一个解决方案似乎更安全,并且似乎在概念上更接近于问题:尽快从浮点数转换为十进制,在十进制类型中执行所有相关计算,然后在写入之前执行最后一分钟转换回浮点DB.
编辑:您可能仍需要在检索浮点值并转换为十进制后立即执行额外的舍入(例如,到3位小数,或适合您的应用程序),以确保最终得到小数值实际上是有意的. 6.925e0
转换为十进制将再次成为可能(假设小数格式具有> 16位精度),以提供非常接近但不完全等于的东西6.925
; 额外的一轮将照顾这一点.
第二种解决方案对我来说看起来并不可靠:如果6.925e0
由于通常的二进制浮点问题,存储的值恰好是一个很小的数量,该怎么办?然后在乘以之后1000
,结果可能仍然是触摸6925
,因此舍入步骤向下舍入而不是向上舍入.如果你知道你的值总是在该点之后最多有3位数,你可以通过在乘以1000 之后做一个额外的回合来解决这个问题ROUND(ROUND(x * 1000, 0), -1)
.
(免责声明:虽然我在处理其他环境中的浮点数和小数问题方面有很多经验,但我对SQL几乎一无所知.)
归档时间: |
|
查看次数: |
8107 次 |
最近记录: |