【问题标题】:Why does DECIMAL behave like FLOAT?为什么 DECIMAL 的行为类似于 FLOAT?
【发布时间】:2018-10-17 12:27:12
【问题描述】:

尽管DECIMAL 是一个精确的数字类型(不像FLOAT,它是近似的),但它在以下示例中的行为相当奇怪:

DECLARE @DECIMAL_VALUE1 DECIMAL(20,9) = 504.70 / 0.151562
DECLARE @DECIMAL_VALUE2 DECIMAL(20,0) = 504.70 / 0.151562
DECLARE @INTEGER_VALUE INT            = 504.70 / 0.151562

SELECT
    @DECIMAL_VALUE1 AS DECIMAL_VALUE1,  -- 3329.990366978
    @DECIMAL_VALUE2 AS DECIMAL_VALUE2,  -- 3330
    @INTEGER_VALUE  AS INTEGER_VALUE    -- 3329

3329 以外的值会导致我们的应用程序出现错误。将变量类型设置为 INTEGER 解决了我们的问题,但我无法弄清楚它最初是为什么引起的。

【问题讨论】:

  • 十进制不是精确的数字类型。当然它具有更高的精度和范围......除非您使用 epsilon 或 delta,否则您永远不应该依赖比较非整数:stackoverflow.com/questions/3420812/…您有 XY 问题吗?
  • 该计算的确切结果是 3329.990366978...,您到底在问什么?
  • DECIMAL 是基数为 10 的浮点类型,与 FLOAT 不同的是基数为 2 的浮点类型。不过,它仍然是浮点数,如果超过支持的小数位数,您可能仍然遇到舍入问题。 504.70 / 0.151562 的结果不能精确地表示为以 10 为基数的有限个数。无论如何,它不是33293330(确切地说是3330 * 0.151562 = 504.70146)。
  • 也许您正在寻找的是FLOOR(504.70 / 0.151562),但如果没有更清楚的说明,则无法回答。

标签: sql-server decimal rounding


【解决方案1】:

你问,“为什么它首先是造成的”:

了解为什么需要了解每种数据类型的性质以及它在 SQL Server 中的运行方式。

  • 整数数学会截断小数(无舍入,与“FLOOR”函数相同(这就是您得到 3329 的原因))。
  • 0 位四舍五入的小数(这就是为什么你会得到 3330 作为 3329.99 的四舍五入)
  • 具有精度/刻度四舍五入到第 N 刻度的十进制(这就是为什么您会得到 3329.990366978...)。

所以这不是意外行为,考虑到所涉及的数据类型,这是意料之中的。这可能只是意料之外的行为。在遇到它们之前,每种数据类型的细微差别都可能存在问题。

我会选择忽略浮动评论,因为它与问题无关。

【讨论】:

    猜你喜欢
    • 2018-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-30
    • 2015-06-20
    • 1970-01-01
    • 1970-01-01
    • 2013-01-04
    相关资源
    最近更新 更多