Здравствуйте, Воронин Иван, Вы писали:
ВИ>Сейчас стал перепроверять и обнаружил мне не понятное поведение.
ВИ>Если играть с точность и масштабом, то точность вычислений меняется и не больше значит больше.
ВИ>Нужно смотреть реализацию, но мне это не до этого.
| подробности |
| ВИ>ВИ>declare @N1 Numeric(20,2)
ВИ>declare @N2 Numeric(20,2)
ВИ>set @N1 = 42183246.61
ВИ>set @N2 = 41761414.14
ВИ>select @N2 * 100 / @N1
ВИ>результат: 98.99999999075462
ВИ>
ВИ>ВИ>declare @N1 Numeric(17,2)
ВИ>declare @N2 Numeric(17,2)
ВИ>set @N1 = 42183246.61
ВИ>set @N2 = 41761414.14
ВИ>select @N2 * 100 / @N1
ВИ>результат: 98.99999999075462342
ВИ>
|
| |
ВИ>Результат в калькуляторе от Win7 в инженерном режиме: 98,999999990754623426553748609157
Предположим, у нас @N1 и @N2 имеют тип
Numeric(x,2) (рубли с копейками).
Согласно
справочнику, типы результатов выводятся следующим образом:
numeric(x, 2) * numeric(3, 0) => numeric(x+4, 2)
numeric(x+4, 2) / numeric(x, 2) => numeric(x + 4 + max(6, x + 3), max(6, x + 3))
Если 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))