Значения значений столбца REAL за пределами документированного диапазона

Согласно 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) ) 

Легко показать, как эти значения попадают в таблицу. Я не могу вставить их напрямую:

 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 

Но я могу разделить два столбца и получить и вне значения диапазона:

 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 

Итак, я предполагаю, что MSDN дает неправильные диапазоны действительных данных, правильно? Я что-то пропустил?

Несколько человек предположили, что это ошибка.

Какая часть этого поведения в точности является ошибкой. это:

  1. Неверные константы, зарегистрированные в MSDN и используемые в DBCC, а также неправильный порог для округления.
  2. Обновление, позволяющее сохранить неправильные значения

    Books Online документирует только нормальный диапазон для чисел с плавающей запятой с одиночной и двойной точностью. Правила IEEE 754 также указывают числа с плавающей запятой ближе к нулю, чем наименьшее ненулевое нормальное значение, известное по-разному как денормализованные, денормальные и субнормальные числа. Из этой последней ссылки:

    Денормальные числа обеспечивают гарантию того, что сложение и вычитание чисел с плавающей запятой никогда не заканчиваются; два соседних числа с плавающей запятой всегда имеют представимую ненулевую разницу. Без постепенного перетока вычитание a-b может быть истощено и получить нуль, даже если значения не равны. Это, в свою очередь, может привести к делению на нулевые ошибки, которые не могут возникнуть при использовании постепенного перетока.

    SQL Server выполняет правила вычисления с плавающей запятой с одинарной точностью в приведенных примерах. Ошибка может заключаться в том, что DBCC проверяет только на нормальные значения и выдает неправильное сообщение об ошибке при обнаружении сохраненного значения денормальности.

    Пример, создающий денормальное значение с одной точностью:

     DECLARE @v1 real = 14e-39, @v2 real = 1e+07; -- 1.4013e-045 SELECT @v1 / @v2; 

    Пример, показывающий сохраненный денормальный файл с 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; 

    Это ошибка в SQL Server. Последний скрипт, который вы публикуете, является хорошим воспроизведением. Добавьте к ней одну строку:

     DBCC CHECKDB WITH data_purity 

    Это не удается:

    Msg 2570, уровень 16, состояние 3, строка 1 Страница (1: 313), слот 0 в ID объекта 357576312, индексный идентификатор 0, идентификатор раздела 1801439851932155904, идентификатор блока ID 2017612634169999360 (введите «данные в строке»). Значение столбца «r3» вне диапазона для типа данных «real». Обновить столбец до юридического значения.

    Это доказывает, что это ошибка. Я предлагаю вам указать ошибку в Microsoft Connect для SQL Server .

    Давайте будем гением компьютера.