Здравствуйте, Воронин Иван, Вы писали: ВИ>Сейчас стал перепроверять и обнаружил мне не понятное поведение. ВИ>Если играть с точность и масштабом, то точность вычислений меняется и не больше значит больше. ВИ>Нужно смотреть реализацию, но мне это не до этого.
Если x >= 3, то выражение упрощается до numeric(2x+7, x+3)
То есть, для x = 17 тип должен получаться numeric(41, 20). Но максимум точности — 38, и тип будет урезан с потерей младших разрядов, то есть в реальности получится numeric(38, 17).
Для x = 20 получаем numeric(47, 23), который урезается до (38, 14)
Давайте повнимательнее посмотрим на процесс урезания. От x+3 мы отнимаем превышение 2x+7 над 38.
То есть если x <= 15, то урезания не произойдёт.
А вот если x > 15, то результирующий масштаб (scale) будет равен x+3 — (2x+7-38) = 34 — x, при точности 38.
Из-за этого вы и наблюдаете такой парадокс: чем больше исходная точность (precision), тем хуже финальный масштаб (scale). SQL server резервирует для вас лидирующие цифры в целой части.
Вы хотите получить 15 знаков после запятой. Решение уравнения напрямую даёт нам x = 19.
Если от вас не требуется оперировать суммами более десяти квадриллионов рублей, то можно просто вычислять вот так:
print cast(41761414.14 as dec(19, 2)) * 100 / cast(42183246.61 as dec(19,2))
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
P.S.
Исследовать поведение автовывода типов удобно при помощи вспомогательной процедуры:
IF OBJECT_ID (N'dbo.Analyse') IS NOT NULL
DROP PROCEDURE dbo.Analyse;
GO
create procedure Analyse(@what sql_variant)
as
begin
print cast(@what as varchar(max))
print
cast(SQL_VARIANT_PROPERTY(@what, 'BaseType') as varchar(max)) +'('+
cast(SQL_VARIANT_PROPERTY(@what, 'Precision') as varchar(max))+ ', ' +
cast(SQL_VARIANT_PROPERTY(@what, 'Scale') as varchar(max)) + ')'
end
go
DECLARE
@foo decimal(19,2) = 41761414.14,
@bar decimal(19,2) = 42183246.61,
@what sql_variant
set @what = @foo / @bar * 100
exec Analyse @what
print cast(41761414.14 as dec(19, 2)) * 100 / cast(42183246.61 as dec(19,2))
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Требуется:
На стороне сервера вычислить процент меньшего от большего с 15 знаками после запятой (всего 17). Самое "длинное" число — 99.999999999999999.
Двойной точности для этого не хватает. В какой-нибудь СУБД есть четверная точность? Судя по поведению, Numeric для деления конвертируется туда и обратно в двойную точность.
Реализовывать аналог BigInteger?
М.б. есть готовые решения?
29.05.2023 16:49, "Воронин Иван" пишет: > Двойной точности для этого не хватает. В какой-нибудь СУБД есть четверная точность? Судя по поведению, Numeric для деления конвертируется туда и обратно в двойную точность. > > Реализовывать аналог BigInteger? > М.б. есть готовые решения?
Здравствуйте, Alex.Che, Вы писали:
AC>29.05.2023 16:49, "Воронин Иван" пишет: >> Двойной точности для этого не хватает. В какой-нибудь СУБД есть четверная точность? Судя по поведению, Numeric для деления конвертируется туда и обратно в двойную точность.
AC>DECIMAL
Типы числовых данных с фиксированными точностью и масштабом. Типы decimal и numeric являются взаимозаменяемыми синонимами.
И не резиновый:
Максимальное общее число хранимых десятичных разрядов. Это число включает символы слева и справа от десятичной запятой. Точность должна быть значением в диапазоне от 1 до максимум 38.
Сейчас стал перепроверять и обнаружил мне не понятное поведение.
Если играть с точность и масштабом, то точность вычислений меняется и не больше значит больше.
Нужно смотреть реализацию, но мне это не до этого.
29.05.2023 18:30, "Воронин Иван" пишет:
> И не резиновый:
резиновый, резиновый.
если при вычислении получившаяся "точность" будет больше указанного значения,
то в результате будет использоваться большая "точность".
Здравствуйте, Alex.Che, Вы писали:
AC>резиновый, резиновый. AC>если при вычислении получившаяся "точность" будет больше указанного значения, AC>то в результате будет использоваться большая "точность".
Результат по своим (точность, масштаб) отличается от аргументов? Я с этим не спорил.
Видимо, у нас разные понимания "резиновости".
Для меня резиновость — это типа BigInteger в .Net.
Здравствуйте, Воронин Иван, Вы писали:
ВИ>Есть:
ВИ>
ВИ>T-SQL (2005); ВИ>2 Numeric'а (рубли с копейками). ВИ>
ВИ>Требуется: ВИ>На стороне сервера вычислить процент меньшего от большего с 15 знаками после запятой (всего 17). Самое "длинное" число — 99.999999999999999.
ВИ>Двойной точности для этого не хватает. В какой-нибудь СУБД есть четверная точность? Судя по поведению, Numeric для деления конвертируется туда и обратно в двойную точность.
Я бы делал CLR Stored Procedure, но не знаю какой dotnet поддерживает 2005 SQL Server и есть ли там длинная математика из коробки. В 2017 так можно.
Здравствуйте, Воронин Иван, Вы писали:
M>>Есть на плюсиках. Можешь сканпелять в DLL и всуячить в сиквел сервер как расширение
ВИ>Я того ещё ни разу не делал. ВИ>Что, потом можно будет использовать в коде как скалярную функцию?
Вроде бы да. Но это не точно На шарпе вроде точно можно делать такие расширения, на плюсах теоретически тоже должно быть возможно, но явно придется потрахаться
Здравствуйте, Sinclair, Вы писали: S>Если от вас не требуется оперировать суммами более десяти квадриллионов рублей, то можно просто вычислять вот так: S>
S>print cast(41761414.14 as dec(19, 2)) * 100 / cast(42183246.61 as dec(19,2))
S>
Спасибо! Всё подходит. Должно сработать.
Тут политика, но она к месту
Если монетарная политика не станет альтернативной (привет Реджепу), то ещё не скоро дойдём до триллиона.
Здравствуйте, Sinclair, Вы писали:
S>Если от вас не требуется оперировать суммами более десяти квадриллионов рублей, то можно просто вычислять вот так: S>
S>print cast(41761414.14 as dec(19, 2)) * 100 / cast(42183246.61 as dec(19,2))
S>
Пока облом.
Забыл упомянуть, что это не своя ИС, а покупная (OLAP). В редакторе источников данных есть вычисляемые поля.
Попробовал реализовать, и выяснил.
При вычислениях (делении точно) они переводят Numeric во Float. К этому коду у меня доступа нет — это в "движке". Не понял зачем.
Именно поэтому у меня зародилось предположение: "Судя по поведению, Numeric для деления конвертируется туда и обратно в двойную точность."
Здравствуйте, Воронин Иван, Вы писали: ВИ>Попробовал реализовать, и выяснил. ВИ>При вычислениях (делении точно) они переводят Numeric во Float. К этому коду у меня доступа нет — это в "движке". Не понял зачем.
Посмотрите, какой SQL порождает этот движок, при помощи SQL Profiler. Если вычисления делаются внутри движка, а не опускаются на уровень SQL, то упс. ВИ>Именно поэтому у меня зародилось предположение: "Судя по поведению, Numeric для деления конвертируется туда и обратно в двойную точность."
Ну, по крайней мере, вы знаете, где именно возникла проблема. Теперь можно сосредоточиться на этом месте:
1. Написать здесь или на stackoverflow конкретный вопрос с минимальным примером OLAP-запроса, на котором воспроизводится косяк
3. Написать в поддержку этого OLAP-решения
Уйдемте отсюда, Румата! У вас слишком богатые погреба.