Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
 Преобразование float -> decimal  [new]
Yuri_dp
Member

Откуда: Днепропетровск
Сообщений: 305
Всем доброго времени суток!

Есть такой вот простой примерчик:
DECLARE @a float(53)

SET @a = 1.2345

SELECT @a

SELECT CAST(@a AS decimal(38, 3))
Хотелось бы при перобразовании float -> decimal избавиться от возможных ошибок, связанных с неточностью типов с плавающей точкой.

В рассмотренном примере прямое преобразование float(53) -> decimal(38, 3) дает ошибочный результат 1.234 - это объяснимо, ведь число хранится как 1.234999999999999.
А хочется получить все же 1.235

Может у кого-то есть мысли по поводу УНИВЕРСАЛЬНОГО решения этой проблемы (для любых чисел) - поделитесь, если не трудно!
27 фев 06, 14:32    [2394730]     Ответить | Цитировать Сообщить модератору
 Re: Преобразование float -> decimal  [new]
pkarklin
Member

Откуда: Москва (Муром)
Сообщений: 74925
Эт с какого перепугу 1.2344999999999999 должно быть 1.235?!
27 фев 06, 14:34    [2394742]     Ответить | Цитировать Сообщить модератору
 Re: Преобразование float -> decimal  [new]
pkarklin
Member

Откуда: Москва (Муром)
Сообщений: 74925
DECLARE @a float(53)

SET @a = 1.2345

SELECT @a

SELECT CAST(@a AS decimal(38, 4))
27 фев 06, 14:35    [2394745]     Ответить | Цитировать Сообщить модератору
 Re: Преобразование float -> decimal  [new]
Guest0
Guest
DECLARE @a float(53)
SET @a = 1.2345
select cast(cast(@a as decimal(38, 4)) as decimal(38, 3))
27 фев 06, 14:37    [2394757]     Ответить | Цитировать Сообщить модератору
 Re: Преобразование float -> decimal  [new]
Yuri_dp
Member

Откуда: Днепропетровск
Сообщений: 305
pkarklin
Эт с какого перепугу 1.2344999999999999 должно быть 1.235?!


1.2344999999999999 и не должно быть 1.235, а вот 1.2345 должно быть.

А ИСХОДНОЕ число у меня 1.2345
27 фев 06, 15:00    [2394891]     Ответить | Цитировать Сообщить модератору
 Re: Преобразование float -> decimal  [new]
Yuri_dp
Member

Откуда: Днепропетровск
Сообщений: 305
По поводу всех вариантов с CAST:
я не зря в вопросе выделил - интересует УНИВЕРСАЛЬНЫЙ метод преобразования. В данном случае понятно - надо откастить (или округлить) до 4 знака, а потом уже до 3.
А еще лучше - до последней значащей цифры, а потом до требуемого разряда.
Но количество знаков, до которого округлять зависит от аргумента.
27 фев 06, 15:03    [2394912]     Ответить | Цитировать Сообщить модератору
 Re: Преобразование float -> decimal  [new]
Yuri_dp
Member

Откуда: Днепропетровск
Сообщений: 305
Пока что дошел только до такого варианта:
DECLARE @a float(53)
SET @a = -1999999999.245
SELECT @a
SELECT ROUND(CAST(@a as decimal(38, 15)), 15 - FLOOR(LOG10(ABS(@a))) - 2)
Гарантированно дает 14 значащих цифр.
Но мне самому не нравится :(
27 фев 06, 15:05    [2394929]     Ответить | Цитировать Сообщить модератору
 Re: Преобразование float -> decimal  [new]
BPK
Member

Откуда: ни: возьмись.
Сообщений: 1601
Yuri_dp
Может у кого-то есть мысли по поводу УНИВЕРСАЛЬНОГО решения этой проблемы (для любых чисел) - поделитесь, если не трудно!

Универсальное решение проблемы - хранить числа как целые, а в нужный момент, перед употреблением, делить их на 10N.
Есть ещё такой тип как money. Этот жёстко зафиксирован на четырёх знаках после запятой. Хранится как целое.
27 фев 06, 15:12    [2394973]     Ответить | Цитировать Сообщить модератору
 Re: Преобразование float -> decimal  [new]
pkarklin
Member

Откуда: Москва (Муром)
Сообщений: 74925
Напишите свою функцию. Но что-то мне трудно понять практическую пользу эдакого последовательного округления.
27 фев 06, 15:13    [2394983]     Ответить | Цитировать Сообщить модератору
 Re: Преобразование float -> decimal  [new]
Glory
Member

Откуда:
Сообщений: 104760
Yuri_dp
По поводу всех вариантов с CAST:
я не зря в вопросе выделил - интересует УНИВЕРСАЛЬНЫЙ метод преобразования. В данном случае понятно - надо откастить (или округлить) до 4 знака, а потом уже до 3.
А еще лучше - до последней значащей цифры, а потом до требуемого разряда.
Но количество знаков, до которого округлять зависит от аргумента.

О какой такой "последней значащей цифры" может идти речь для изначально _неточных типов данных_ ?
Сколько значящих цифр у числа PI к примеру ?
27 фев 06, 15:15    [2394993]     Ответить | Цитировать Сообщить модератору
 Re: Преобразование float -> decimal  [new]
Yuri_dp
Member

Откуда: Днепропетровск
Сообщений: 305
Glory
О какой такой "последней значащей цифры" может идти речь для изначально _неточных типов данных_ ?
Сколько значящих цифр у числа PI к примеру ?

Вообще-то количество значащих цифр не зависит от ЗНАЧЕНИЯ, а зависит от точности его измерения (в нашем случае - хранения).
Поэтому в нашем случае количество значащих цифр - это, строго говоря, разрядность мантиссы этого числа, представленного в стандартном виде.
Изначальная неточность типов с плавающей точкой проявляется в появлении погрешности в ПОСЛЕДНЕМ разряде. Поэтому если тип double, согласно документации, обеспечивает 15 значащих цифр, то после ОКРУГЛЕНИЯ до предоследнего (14) значащего разряда мы получаем точное значение.

Практическое значение всех этих извращений очень простое.
Предположим, в системе числа хранятся в полях таблиц с точным типом decimal (money изначально не подходит - ТЗ требует точности вычислений хотя бы до 7 знаков после запятой). С этими числами производятся сложные вычисления. Учитывая особенности неявного преобразования типов при умножении и делении аргументов типа decimal, принято решение все вычисления производить во float. Таким образом, обеспечивается точность вычислений 15 значащих цифр. Это проверялось экспериментально.
Конечный результат вычислений получается во float. После этого требуется его снова преобразовать в decimal с заданной точностью. Проблема - как раз в этом преобразовании, и связана она как раз с неточным хранением во float, когда из-за ошибки в 16-17 разряде я получаю неправильное округление, например, до 3 разряда (см. выше).
27 фев 06, 15:34    [2395122]     Ответить | Цитировать Сообщить модератору
 Re: Преобразование float -> decimal  [new]
Yuri_dp
Member

Откуда: Днепропетровск
Сообщений: 305
pkarklin
Напишите свою функцию. Но что-то мне трудно понять практическую пользу эдакого последовательного округления.


Ну вот свою функцию я и напишу скорей всего по тому алгоритму, который выше приводил.

Просто меня не оставляет ощущение, что есть более правльное решение.
27 фев 06, 16:11    [2395344]     Ответить | Цитировать Сообщить модератору
 Re: Преобразование float -> decimal  [new]
aleksey_fomchenko
Member

Откуда: Москва
Сообщений: 1014
Здравствуй Юрий.

Есть флаг трассировки:
DBCC TRACEON 107 - Интерпретирует числа с точкой как числа с плавающей точкой вместо decimal.

Возможно кто либо знает флаг, интерпритирующий чила обратно (float->decimal) по одному методу.
27 фев 06, 16:32    [2395441]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить