Вкратце — результат вычисляется не как float, а как тип левого аргумента функции. При этом тип левого аргумента должен иметь способность неявного преобразования в float.
Здравствуйте, Аноним, Вы писали:
А>Посмотрите на этот пример: А>почему так?
POWER ( float_expression , y )
Функция Power возвращает результат такого же типа, который передается в аргументе float_expression Когда вы делаете сложение @n + 1.0 на выходе получаете тип numeric(12, 1), т.е. 1 знак после запятой. Соответственно Power результат вычисления округляет до 1 знака. Если ваш пример является головоломкой, то распутать ее можно повышая точность для 1 на n знаков, чем больше n тем точнее результат получится. Посмотрите пример ниже:
Здравствуйте, Аноним, Вы писали:
А>Есть мелкте детали "на выходе получаете тип numeric(12, 1)" — почему не numeric(10, 1), например?
При выполнении операций с разными типами данных SQL Server использует приоритет типов данных (Data Type Precedence), когда тип данных с меньшим приоритетом неявно преобразуется к типу данных с большим приоритетом (если это возможно!). Вы оперируете двумя типами данных – int и numeric. Т.к. int имеет более низкий приоритет, то все выражение @n + 1.0 приводится к типу numeric. По ссылке, которую я приложил можно посмотреть типы и их приоритеты.
Выбор длины результирующего типа, основывается на размерах типов данных, которые складываются. У вас два значения @n и 1.0, где…
@n является целым (int) и содержит всего 10 цифр (precision)
1.0 является numeric(2, 1), причем содержит всего две цифры (precision), одна из которых после запятой справа (scale)
Соответственно, складывая параметры scale и precision, на выходе получаем результирующий тип длиной 12 цифр, причем 1 из них справа после запятой. Все вышесказанное можно проверить, используя функцию sql_variant_property
declare @n int
set @n = 1
-- Для @nselect
sql_variant_property(@n, 'BaseType') as Type
,sql_variant_property(@n, 'Precision') as Precision
,sql_variant_property(@n, 'Scale') as Scale
-- Для 1.0select
sql_variant_property(1.0, 'BaseType') as Type
,sql_variant_property(1.0, 'Precision') as Precision
,sql_variant_property(1.0, 'Scale') as Scale
-- Для @n + 1.0 select
sql_variant_property(@n + 1.0, 'BaseType') as Type
,sql_variant_property(@n + 1.0, 'Precision') as Precision
,sql_variant_property(@n + 1.0, 'Scale') as Scale
А>А в общем, так как они сделали это логично? Не является ли это дефектом? Получаются колоссальные потери точности
Дефектов нет, все в порядке Поведение предсказуемое и описано в документации. Ну а чтобы избегать потерь точности, нужно аккуратно выбирать и применять типы данных, в принципе как и везде.
Re[4]: Признаю, был не прав в методике расчета точности и масштаба…
Коллеги, приношу извинения, если кого-то ввёл в заблуждение своими вычислениями точности и масштаба результирующего типа. Правильная методика в корне отличается от той, которую я привел. Оригинал находится здесь Precision, Scale, and Length (Transact-SQL), там описаны формулы для всех операций.
В частности, для сложения двух чисел e1(p1,s1) + e2(p2, s2) = e3(p3, s3), используется формула p3 = max(s1, s2) + max(p1-s1, p2-s2) + 1 и s3 = max(s1, s2), где
pN – точность числа (общее кол-во цифр в числе)
sN – масштаб числа (кол-во цифр после запятой)
N = 1,2 — первое и второе слагаемое
N = 3 — результат сложения
Рассмотрим более сложный пример на двух числах @m и @n
declare @m int = 10 (p1 = 10, s1 = 0)
declare @n numeric(34, 3) = 1.0 (p2 = 34, s2 = 3)
рассчитываем точность и масштаб для e3(p3, s3)
p3 = max(0, 3) + max(10 – 0, 34 – 3) + 1 = 35, s3 = max(0, 3) = 3
В итоге, на выходе с учетом старшинства типов получаем numeric(35, 3)
Код
Скрытый текст
declare @n numeric(34, 3)
set @n = 0
declare @m int
set @m = 0
-- Для @nselect
sql_variant_property(@n, 'BaseType') as Type
,sql_variant_property(@n, 'Precision') as Precision
,sql_variant_property(@n, 'Scale') as Scale
-- Для @mselect
sql_variant_property(@m, 'BaseType') as Type
,sql_variant_property(@m, 'Precision') as Precision
,sql_variant_property(@m, 'Scale') as Scale
-- Для @n + @mselect
sql_variant_property(@n + @m, 'BaseType') as Type
,sql_variant_property(@n + @m, 'Precision') as Precision
,sql_variant_property(@n + @m, 'Scale') as Scale
Re[5]: Признаю, был не прав в методике расчета точности и масштаба…
Здравствуйте, Olaf, Вы писали:
O>Коллеги, приношу извинения, если кого-то ввёл в заблуждение своими вычислениями точности и масштаба результирующего типа. Правильная методика в корне отличается от той, которую я привел. Оригинал находится здесь Precision, Scale, and Length (Transact-SQL), там описаны формулы для всех операций.
Спасибо за то, что откликнулись на эту тему. Детали-то там находятся все по ссылке из предыдущего сообщения
Help will always be given at Hogwarts to those who ask for it.
Re[6]: Признаю, был не прав в методике расчета точности и масштаба…