11

我用浮点计算做了一些测试,以尽量减少精度损失。我偶然发现了一个我想在这里展示的现象,希望能得到解释。

当我写

print 1.0 / (1.0 / 60.0)

结果是

60.0024000960

当我编写相同的公式并进行显式转换时float

print cast(1.0 as float) / (cast(1.0 as float) / cast(60.0 as float))

结果是

60

到目前为止,我认为带小数位的数字文字会自动被视为float具有适当精度的值。投射到real显示与投射到 相同的结果float

  • 是否有一些关于 SQL Server 如何评估数字文字的文档?
  • 这些文字属于什么数据类型?
  • 我真的必须铸造它们以float获得更好的精度(这对我来说听起来很讽刺:)?
  • 有没有比将我的公式与演员表混为一谈更简单的方法?
4

4 回答 4

10

SQL Server 使用尽可能小的数据类型。

当你运行这个脚本

SELECT SQL_VARIANT_PROPERTY(1.0, 'BaseType')
SELECT SQL_VARIANT_PROPERTY(1.0, 'Precision')
SELECT SQL_VARIANT_PROPERTY(1.0, 'Scale')
SELECT SQL_VARIANT_PROPERTY(1.0, 'TotalBytes')

您会看到 SQL Server 隐式使用了 NUMERIC(2, 1) 数据类型。
除以 60.0 将结果转换为 NUMERIC(8, 6)。
最终计算将结果转换为 NUMERIC(17, 10)。


编辑

取自 SQL Server 联机丛书数据类型转换

在 Transact-SQL 语句中,带小数点的常量会自动转换为数字数据值,使用所需的最小精度和小数位数。例如,常数 12.345 被转换为精度为 5、小数位数为 3 的数值。

于 2009-07-02T06:58:14.423 回答
4

是的,您经常必须将它们转换为浮动以获得更好的精度。我的看法:

为了在计算前获得更好的精度转换小数

于 2009-07-02T15:19:31.200 回答
3

我认为应该了解幕后发生的事情,以供将来在类似情况下参考。

不包括科学记数法的带小数点的文字数值表示 Decimal 数据类型,该数据类型存储为尽可能小的 Decimal 类型。与 Lieven Keersmaekers 的引用相同: https ://msdn.microsoft.com/en-us/library/ms191530%28SQL.90%29.aspx#_decimal

在 Transact-SQL 语句中,带小数点的常量会自动转换为数字数据值,使用所需的最小精度和小数位数。例如,常数 12.345 被转换为精度为 5、小数位数为 3 的数值。

小数点右侧的尾随零指定比例。小数点左边的前导零被忽略。

一些例子:

1.0  -> Decimal(2,1)
60.0 -> Decimal(3,1)
1.00 -> Decimal(3,2)
01.0 -> Decimal (2,1)

要考虑的另一点是数据类型优先级。当运算符组合不同数据类型的两个表达式时,数据类型优先级规则指定将具有较低优先级的数据类型转换为具有较高优先级的数据类型。还有一点要考虑的是,如果我们对 Decimal 类型进行算术运算,那么得到的 Decimal 类型,即精度和小数位数取决于操作数和运算本身。这在文档Precision、Scale 和 Length中有描述。

所以,括号中的部分表达式

( 1.0 / 60.0 ) is evaluated to 0.016666 and the resulting type is Decimal (8,6)

使用上述有关小数表达式的精度和比例的规则。此外,使用银行家的四舍五入或四舍五入。重要的是要注意使用了 Decimal 和 float 类型的不同舍入。如果我们继续表达

1.0 / 0.016666 is evaluated to 60.002400096 and the resulting type is Decimal (17,10)

因此,差异的部分原因是用于十进制类型的舍入与浮点类型不同。

根据上述规则,在括号内只使用一个转换就足够了。根据数据类型优先级规则,所有其他文字都将被提升为浮动。

1.0 / (1.0 / cast(60.0 as float))

还有一件重要的事情。即使这个浮点表达式也不能计算出准确的结果。只是为了让前端(SSMS 或其他)将值四舍五入(我猜)精度为 6 位,然后截断尾随零。因此,即 1.000001 变为 1。

很简单,不是吗?

于 2015-09-11T21:31:00.560 回答
0

要编写一个常量浮点表达式,请尝试使用科学计数法:

select (1.0E0 / (1.0E0 / 60.0E0))

结果是60。

于 2019-01-15T19:39:04.103 回答