【问题标题】:SQL Round cast to floatSQL Round 转换为浮动
【发布时间】:2017-09-14 08:05:25
【问题描述】:

我在 SQL Server 2014 中遇到了舍入问题:当我将一个数字舍入到小数点后 2 位时,如果我之前转换为浮点数,则舍入的数字有时会有所不同。 例如,如果我执行:

select round(cast(3.945 as float),2)
select round(3.945,2)

我有:

3.94
3.950

但如果我执行:

select round(cast(3.935 as float),2)
select round(3.935,2)

我有:

3.94
3.940

似乎不正确,将 3.935 和 3.945 转换为浮动之前,我得到了相同的值。这是一个错误吗?

【问题讨论】:

  • 正常浮点行为。如果需要精确值,请使用十进制数据类型。
  • Float 是一个approximate data type,你不能保证它会产生正确的值,它总是会给你一个可能正确或不正确的近似值,如果你关心数据的准确性使用确切的数据类型,例如 DECIMAL(18,2)
  • 仅供参考:除了cast(3.945 as float),您还可以使用3.945E03945E-3 / 其变体作为另一种获得浮点文字的方式。这对您描述的行为没有影响;顺便说一句。

标签: sql sql-server casting rounding


【解决方案1】:

这里的问题是 float 是二进制浮点类型,其中表示是值的近似值。浮点数不会无损地转换为基数 10 或从基数 10 转换,因为没有 10 的幂,它也是 2 的幂。因此,当它被转换时,它的完成方式会留下一个舍入误差,该误差会在舍入之前推动值阈值。

奇怪的是,我无法在 PostgreSQL 上重现相同的行为,我也不完全确定原因(可能是在 PostgreSQL 上,round 需要一个数值,这会强制转换回来)。

切勿在需要绝对精度的情况下使用浮点数。这不仅发生在数据库中,而且几乎在所有编程语言中都发生。

【讨论】:

    【解决方案2】:

    正如@ChrisTravers 在his answer 中所说,四舍五入浮点数的问题是您没有得到精确的算术。也就是说,这解释了为什么round(3.945,2) 向上舍入为3.95round(3.945E0,2) 有效地向下舍入为3.94

    如果您想知道为什么在某些情况下会看到超过 2 位小数,那是因为您正在处理的类型。即3.94 是一个浮点数,因此没有指定的小数位数;而3.950 是对decimal(4,3) 进行四舍五入的结果;即使我们已经四舍五入到小数点后 2 位,也不会影响类型的精度(即它仍然是 decimal(4,3);未转换为 decimal(4,2)decimal(3,2))。

    如果此舍入的目的是为了显示,您最好使用str 函数。即

    • select str(3.945,4,2) --decimal
    • select str(3.945E0,4,2) --float

    在上面的 4 是字符串的长度(即包括小数点作为字符),2 是要显示的小数位数。 注意:在这种情况下,您将数据类型更改为varchar(4)

    下面的代码可以让你查看执行操作后得到的类型:

    declare @result sql_variant = str(3.945E0,4,2)
    
    select sql_variant_property(@result, 'BaseType') [BaseType]
    ,sql_variant_property(@result, 'MaxLength') [MaxLength]
    ,sql_variant_property(@result, 'Precision') [Precision]
    ,sql_variant_property(@result, 'Scale') [Scale]
    

    【讨论】:

      猜你喜欢
      • 2018-01-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-21
      • 1970-01-01
      • 1970-01-01
      • 2014-04-16
      相关资源
      最近更新 更多