Кто-нибудь знает, почему, используя SQLServer 2005
SELECT CONVERT(DECIMAL(30,15),146804871.212533)/CONVERT(DECIMAL (38,9),12499999.9999)
дает мне 11.74438969709659,
но когда я увеличиваю десятичные знаки в знаменателе до 15, я получаю менее точный ответ:
SELECT CONVERT(DECIMAL(30,15),146804871.212533)/CONVERT(DECIMAL (38,15),12499999.9999)
дай мне 11.74438969





Преобразуйте выражение, а не аргументы.
select CONVERT(DECIMAL(38,36),146804871.212533 / 12499999.9999)
Для умножения мы просто складываем количество десятичных знаков в каждом аргументе вместе (используя ручку и бумагу), чтобы вычислить выходные десятичные разряды.
Но разделение просто разносит вам голову. Я иду лечь.
Однако в терминах SQL это именно так, как ожидалось.
--Precision = p1 - s1 + s2 + max(6, s1 + p2 + 1)
--Scale = max(6, s1 + p2 + 1)
--Scale = 15 + 38 + 1 = 54
--Precision = 30 - 15 + 9 + 54 = 72
--Max P = 38, P & S are linked, so (72,54) -> (38,20)
--So, we have 38,20 output (but we don use 20 d.p. for this sum) = 11.74438969709659
SELECT CONVERT(DECIMAL(30,15),146804871.212533)/CONVERT(DECIMAL (38,9),12499999.9999)
--Scale = 15 + 38 + 1 = 54
--Precision = 30 - 15 + 15 + 54 = 84
--Max P = 38, P & S are linked, so (84,54) -> (38,8)
--So, we have 38,8 output = 11.74438969
SELECT CONVERT(DECIMAL(30,15),146804871.212533)/CONVERT(DECIMAL (38,15),12499999.9999)
Вы можете проделать ту же математику, если будете следовать это правило, если вы будете рассматривать каждую пару чисел как
Спасибо. Честно говоря, я использовал FLOAT для моей конкретной проблемы (поскольку мне не нужно быть на 100% точным), но я был чертовски сбит с толку, когда я использовал десятичные дроби.
SQL-сервер, к сожалению, очень плох в арифметике :( Итак, также стоит упомянуть, что, если вам нужны точные результаты для умножения и деления в t-sql, лучшим вариантом является: Определение и использование функций CLR. См .: skylinetechnologies.com/Insights/Skyline-Blog/March-2013/… для хорошее вступление
Короче говоря, используйте DECIMAL (25,13), и вы будете в порядке со всеми вычислениями - вы получите заявленную точность: 12 цифр до десятичной точки и 13 десятичных цифр после. Правило: p + s должно быть равно 38, и вы будете в безопасности! Почему это? Из-за очень плохой реализации арифметики в SQL Server! Пока они не исправят это, следуйте этому правилу.
Есть ли какой-нибудь справочный материал, чтобы сказать, почему это будет «хорошо» для всех расчетов?
select cast(1000000 as DECIMAL(38,19)) / cast(9223372036854775807 as DECIMAL(38,19)); << OK select cast(1000000 as DECIMAL(25,13)) / cast(9223372036854775807 as DECIMAL(25,13)); << Арифметическое переполнение
Я заметил, что если вы приведете значение деления к float, это даст вам правильный ответ, то есть:
select 49/30 (result = 1)
станет:
select 49/cast(30 as float) (result = 1.63333333333333)
Стоит отметить, что с этим типом литья следует быть осторожным и не использовать его вслепую. Десятичные дроби и числа с плавающей запятой хранят представления чисел по-разному, а числа с плавающей запятой имеют некоторые неинтуитивные эффекты, о которых вы должны знать, когда делаете это. Например: select cast (cast (0.1 as float) as decimal (38,18)) Дает результат: 0.100000000000000006 Это потому, что 0.1 не может быть точно представлено в двоичном формате, поэтому он сохраняет что-то немного неточное. Это может оказать влияние, когда вы начнете умножать или округлять значения, поскольку результат может быть немного неверным.
Мы ломали голову над волшебным переходом,
P & S are linked, so:
(72,54) -> (38,29)
(84,54) -> (38,8)
Предполагая, что (38,29) - это опечатка и должен быть (38,20), математика следующая:
я. 72 - 38 = 34, II. 54 - 34 = 20
я. 84 - 58 = 46, II. 54 - 46 = 8
И это рассуждение:
я. Точность вывода минус максимальная точность - это цифры, которые мы собираемся выбросить.
II. Тогда масштаб вывода за вычетом того, что мы собираемся выбросить, дает нам ... оставшиеся цифры в масштабе вывода.
Надеюсь, это поможет кому-нибудь еще, пытаясь разобраться в этом.
Опечатка (должно быть i. 84 - 38 (не 58) = 46, ii. 54 - 46 = 8). Это очень полезно @Campey
Может помочь следующее:
SELECT COL1 * 1.0 / COL2
Почему ты так думаешь?
Кстати, калькулятор Windows дает 11.744389697096595117576772760941