浮点值的"上半部分"

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确实轮半起来,但由于浮点数不能准确地表示十进制数,"错误"的结果(从视终端用户的点)被显示.我理解为什么会这样.

我已经提出了两个可能的解决方案(两个都返回一个浮点数,不幸的是,这也是一个要求):

  1. 舍入前转换为十进制数据类型: SELECT CONVERT(float, ROUND(CONVERT(decimal(29,14), 6.925e0), 2))
  2. 乘以直到第三个数字位于小数点的左侧(即精确表示),然后进行舍入: SELECT ROUND(6.925e0 * 1000, -1) / 1000

我应该选择哪一个?有更好的解决方案吗?(遗憾的是,由于某些遗留应用程序访问同一个数据库,我们无法更改数据库中的字段类型.)

是否存在针对此(常见?)问题的完善的最佳实践解决方案?

(显然,常规技术"四舍五入"在这里没有用,因为6.925已经四舍五入到小数点后三位 - 只要这可以在浮点数中.)

Mar*_*son 6

你的第一个解决方案似乎更安全,并且似乎在概念上更接近于问题:尽快从浮点数转换为十进制,在十进制类型中执行所有相关计算,然后在写入之前执行最后一分钟转换回浮点DB.

编辑:您可能仍需要在检索浮点值并转换为十进制后立即执行额外的舍入(例如,到3位小数,或适合您的应用程序),以确保最终得到小数值实际上是有意的. 6.925e0转换为十进制将再次成为可能(假设小数格式具有> 16位精度),以提供非常接近但不完全等于的东西6.925; 额外的一轮将照顾这一点.

第二种解决方案对我来说看起来并不可靠:如果6.925e0由于通常的二进制浮点问题,存储的值恰好是一个很小的数量,该怎么办?然后在乘以之后1000,结果可能仍然是触摸6925,因此舍入步骤向下舍入而不是向上舍入.如果你知道你的值总是在该点之后最多有3位数,你可以通过乘以1000 之后做一个额外的回合来解决这个问题ROUND(ROUND(x * 1000, 0), -1).

(免责声明:虽然我在处理其他环境中的浮点数和小数问题方面有很多经验,但我对SQL几乎一无所知.)