REAL列保持值在记录范围之外

A-K*_*A-K 5 sql-server data-integrity sql-server-2008 sql-server-2008-r2

根据MSDN,REAL值的范围是 - 3.40E + 38到-1.18E - 38,0和1.18E - 38到3.40E + 38.但是,我的表中有很多超出该范围的值.

以下查询返回许多非常小的值,而不是很大的值:

SELECT  MyColumn ,
        *
FROM    data.MyTable
WHERE   MyColumn <> 0
        AND ( MyColumn < CONVERT(REAL, 1.18E-38)
              OR MyColumn > CONVERT(REAL, 3.40E+38)
            )
        AND ( MyColumn < CONVERT(REAL, -3.40E+38)
              OR MyColumn > CONVERT(REAL, -1.18E-38)
            ) 
Run Code Online (Sandbox Code Playgroud)

很容易显示这些值如何在表中结束.我不能直接插入它们:

CREATE TABLE a(r REAL NULL);
GO
INSERT INTO a(r) VALUES(4.330473E-39);
GO
SELECT r FROM a
GO
DROP TABLE a;

----
0.0
Run Code Online (Sandbox Code Playgroud)

但是我可以划分两列并且超出范围值:

CREATE TABLE a
  (
    r1 REAL NULL ,
    r2 REAL NULL ,
    r3 REAL NULL
  ) ;
GO
INSERT  INTO a
        ( r1, r2 )
VALUES  ( 4.330473E-38, 1000 ) ;
GO
UPDATE  a
SET     r3 = r1 / r2 ;
SELECT  r1 ,
        r2 ,
        r3
FROM    a

r1            r2            r3
------------- ------------- -------------
4.330473E-38  1000          4.330433E-41
Run Code Online (Sandbox Code Playgroud)

所以我猜MSDN给出错误的有效数据范围,对吗?我错过了什么吗?

有几个人认为这是一个错误.

这种行为的哪一部分确实是一个错误.是吗:

  1. MSDN中记录的错误常量并用于DBCC,以及舍入错误的阈值.
  2. 更新能够保存错误的值

小智 7

联机丛书仅记录单精度和双精度浮点数的正常范围.该IEEE 754的规则还可以指定浮点数比最小的非零正常值,不同地称作接近零非规范化,反规范,和次正规号码.从最后一个链接:

非正规数提供了保证浮点数的加法和减法永不下溢; 两个附近的浮点数始终具有可表示的非零差异.在没有逐渐下溢的情况下,即使值不相等,减法a-b也可以下溢并产生零.反过来,这可以导致除以使用逐渐下溢时不会发生的零错误.

SQL Server遵循发布的示例中的单精度浮点计算规则.该错误可能是DBCC仅检查正常值,并在遇到存储的非正常值时抛出不正确的错误消息.

生成非正规单精度值的示例:

DECLARE
    @v1 real = 14e-39,
    @v2 real = 1e+07;

-- 1.4013e-045
SELECT @v1 / @v2;
Run Code Online (Sandbox Code Playgroud)

显示存储的float非正规的示例通过DBCC检查:

CREATE TABLE dbo.b (v1 float PRIMARY KEY);
INSERT b VALUES (POWER(2e0, -1075));
SELECT v1 FROM b; -- 4.94065645841247E-324
DBCC CHECKTABLE(b) WITH DATA_PURITY; -- No errors or warnings
DROP TABLE dbo.b;
Run Code Online (Sandbox Code Playgroud)

  • 哪个部分是错误取决于SQL Server程序员的*意图*.从文档(和`DBCC CHECKDB`)看,*intent*仅存储规范化数字. (4认同)