为什么 SQL Server 允许超出 Microsoft 指定范围的 float(53) 值?

Bra*_*rad 6 sql-server-2005 sql-server-2008 sql-server floating-point

我有一个特定的表,列数据类型为 float(53),非空。根据Microsoft 文档,可以存储在此数据类型中的 0 以上的最小值是 2.23E-308。但是,我能够存储一个小得多的值,小到 4.94065645841247E-324。请参阅下图,证明 SQL Server 可以存储和检索文档中指定范围之外的值:

查询显示非常小的浮点数

当我运行如下查询时:

select 4.7E-309
Run Code Online (Sandbox Code Playgroud)

SQL Server 说: Warning: the floating point value '4.7E-309' is too small. It will be interpreted as 0.

截图中插入的值是通过 C++ ADO 接口使用记录绑定插入的。

我有几个问题:

为什么 SQL Server 处理文档中指定范围之外的值?同样,当查询中存在“超出范围”值时,为什么 SQL Server 会发出警告,而数据库显然可以存储超出该范围的值?

浮点数是如何存储在 SQL 数据库表上的,是否有任何 SQL 服务器设置会严格执行一个 SQL 服务器而不是另一个 SQL 服务器上的范围?

我正在尝试解决 ADO 记录绑定(可能)由于值超出范围而被拒绝的问题,但是我所有重现该问题的测试(在不同的 SQL 服务器实例上)表明 SQL 接受的值远远超出文档中指定的限制。任何有关如何在 SQL 中存储和处理浮点的信息(特别是与 .NET 或 C++ 之类的东西有关)将不胜感激。

我已经使用 SQL Server 2005 和 2008 对此进行了测试,结果相同。

Rem*_*anu 7

我怀疑这是一个验证错误(即错误)。不会是第一个,特别是在 2005-2008 年(我认为 2012 年推动了大数据纯度修复)。我怀疑 aDBCC CHECKDB WITH DATA_PURITY会抱怨价值。

SQL Server 将浮点数存储为 IEEE 754,与 .Net 和 C++ 表示它们的方式相同。64 位可以表示高于和低于 2.23E-308 的值,正如您已经发现的4.94065645841247E-324(即 0x0000000000000001 解释为浮点数)。但是这样的值不符合 IEE754 的另一个要求,即再现性

该标准要求在基本格式和外部字符序列格式之间进行转换的操作。所有格式都需要与十进制字符格式之间的转换。转换为外部字符序列必须使用舍入到偶数转换回原始数字。不需要保留 NaN 或信令 NaN 的有效载荷,从外部字符序列的转换可能会将信令 NaN 变成安静的 NaN。

原始二进制值将通过转换为十进制并再次使用:

  • binary16 的 5 位十进制数字
  • binary32 的 9 位十进制数字
  • binary64 的 17 位十进制数字
  • binary128 的 36 位十进制数字

此要求将限制置于记录的数字上:

  • 1.79E+308 到 -2.23E-308, 0 和 2.23E-308 到 1.79E+308

事实上,ADO 绑定基本上允许将任何位组合作为值传递,并且 SQL Server 接受绑定缓冲区而无需验证,这会导致您注意到的行为。从技术上讲,您以这种方式插入的数据是损坏的。同样,我怀疑 a) 较新版本的引擎在写入之前验证缓冲区(换句话说,它们捕获无效值)并且 b)WITH DATA_PURITY检查将报告问题(即使在 2005/2008/R2 版本上)。

  • 为对未来感兴趣的任何人提供一些附加信息。看起来这是以下错误修复的结果:https://support.microsoft.com/en-ca/kb/942904 (2认同)