Точность десятичного деления T-SQL

Кто-нибудь знает, почему, используя 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

Кстати, калькулятор Windows дает 11.744389697096595117576772760941

inspite 08.01.2009 14:53
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
27
1
49 835
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

Преобразуйте выражение, а не аргументы.

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)

Вы можете проделать ту же математику, если будете следовать это правило, если вы будете рассматривать каждую пару чисел как

  • 146804871.212533000000000 и 12499999.999900000
  • 146804871.212533000000000 и 12499999.999900000000000

Спасибо. Честно говоря, я использовал FLOAT для моей конкретной проблемы (поскольку мне не нужно быть на 100% точным), но я был чертовски сбит с толку, когда я использовал десятичные дроби.

MT. 08.01.2009 16:18

SQL-сервер, к сожалению, очень плох в арифметике :( Итак, также стоит упомянуть, что, если вам нужны точные результаты для умножения и деления в t-sql, лучшим вариантом является: Определение и использование функций CLR. См .: skylinetechnologies.com/Insights/Skyline-Blog/March-2013/… для хорошее вступление

Veysel Ozdemir 20.03.2016 00:36

Короче говоря, используйте DECIMAL (25,13), и вы будете в порядке со всеми вычислениями - вы получите заявленную точность: 12 цифр до десятичной точки и 13 десятичных цифр после. Правило: p + s должно быть равно 38, и вы будете в безопасности! Почему это? Из-за очень плохой реализации арифметики в SQL Server! Пока они не исправят это, следуйте этому правилу.

Есть ли какой-нибудь справочный материал, чтобы сказать, почему это будет «хорошо» для всех расчетов?

MrEdmundo 05.11.2013 21:11
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)); << Арифметическое переполнение
Triynko 27.03.2017 08:17

Я заметил, что если вы приведете значение деления к 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 не может быть точно представлено в двоичном формате, поэтому он сохраняет что-то немного неточное. Это может оказать влияние, когда вы начнете умножать или округлять значения, поскольку результат может быть немного неверным.

Simon P Stevens 27.02.2020 12:11

Мы ломали голову над волшебным переходом,

P & S are linked, so:

  1. (72,54) -> (38,29)

  2. (84,54) -> (38,8)

Предполагая, что (38,29) - это опечатка и должен быть (38,20), математика следующая:

  1. я. 72 - 38 = 34, II. 54 - 34 = 20

  2. я. 84 - 58 = 46, II. 54 - 46 = 8

И это рассуждение:

я. Точность вывода минус максимальная точность - это цифры, которые мы собираемся выбросить.

II. Тогда масштаб вывода за вычетом того, что мы собираемся выбросить, дает нам ... оставшиеся цифры в масштабе вывода.

Надеюсь, это поможет кому-нибудь еще, пытаясь разобраться в этом.

Опечатка (должно быть i. 84 - 38 (не 58) = 46, ii. 54 - 46 = 8). Это очень полезно @Campey

George Joseph 24.02.2021 08:56

Может помочь следующее:

SELECT COL1 * 1.0 / COL2

Почему ты так думаешь?

default locale 16.03.2017 13:30

Другие вопросы по теме