select POWER(2.,64.)
возвращается 18446744073709552000
вместо 18446744073709551616
. Кажется, он имеет только 16 цифр точности (округляя до 17-го).
Даже делая точность явной, select power(cast(2 as numeric(38,0)),cast(64 as numeric(38,0)))
она все равно возвращает округленный результат.
Это кажется довольно простой операцией для произвольного отслаивания с точностью до 16 цифр. Наивысшая можно правильно рассчитать только POWER(2.,56.)
, стенает POWER(2.,57.)
. Что здесь происходит?
Что действительно ужасно, так это то, что на select 2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.*2.;
самом деле возвращает правильное значение. Так много для краткости.
источник
Ответы:
Из онлайн-документации :
Подразумевается, что все, что вы передадите в качестве первого параметра, будет неявно приведено к
float(53)
перед выполнением функции. Однако это не (всегда?) Случай .Если бы это было так, это объяснило бы потерю точности:
С другой стороны, литерал
2.
типаnumeric
...dbfiddle здесь
… И оператор умножения возвращает тип данных аргумента с более высоким приоритетом .
Похоже, что в 2016 году (SP1) вся точность сохраняется:
dbfiddle здесь
… Но в 2014 году (SP2) они не являются:
dbfiddle здесь
источник
POWER(2.,56.) = 72057594037927936
но не выше. Я думаю, мне придется написать свою собственную функцию POWER, которая просто умножается в цикле, смеется.Результат 2 64 точно представлен в
float
(иreal
в этом отношении).Проблема возникает, когда этот точный результат преобразуется обратно в
numeric
(тип первогоPOWER
операнда).До введения уровня совместимости базы данных 130 SQL Server округлялся
float
доnumeric
неявных преобразований до 17 цифр.При уровне совместимости 130 максимально возможная точность сохраняется во время преобразования. Это задокументировано в статье базы знаний:
Улучшения SQL Server 2016 в обработке некоторых типов данных и необычных операций
Чтобы воспользоваться этим в базе данных SQL Azure, необходимо установить
COMPATIBILITY_LEVEL
значение 130:Тестирование рабочей нагрузки необходимо, потому что новая схема не является панацеей. Например:
... должен выдать ошибку, потому что 10 38 не может быть сохранен в
numeric
(максимальная точность 38). Ошибка переполнения приводит к несовместимости 120, но результат ниже 130:источник
С небольшой математикой мы можем найти обходной путь. Для странных
n
:Для четных
n
:Один из способов написать это в T-SQL:
Протестировано на SQL Server 2008, результат 144115188075855872 вместо 144115188075855870.
Это работает вплоть до показателя степени 113. Похоже, что NUMERIC (38,0) может хранить до 2 ^ 126, поэтому не совсем полное покрытие, но формула может быть разбита на несколько частей при необходимости ,
источник
Просто для удовольствия, рекурсивное решение CTE:
источник