Приведение столбца SQL Server из реального в плавающий без внесения небольших ошибок

#sql-server #casting #floating-point #precision

#sql-server #Кастинг #с плавающей запятой #точность

Вопрос:

Я работаю с базой данных SQL Server, где мне нужно получить данные из столбца с типом real в другой столбец в другой таблице с типом float . Насколько я понимаю, real это, по сути, просто float с меньшей точностью (24), по сравнению с float которой по умолчанию имеет точность 53. Поэтому при приведении из real в float я ожидал бы получить большую точность или, по крайней мере, не потерять точность исходного значения. Однако при этом, похоже, теряется некоторая точность:

Преобразование реального в плавающий

Почему это происходит и есть ли способ хотя бы сохранить точность исходных значений при этом?

Комментарии:

1. Реальный вопрос заключается в том, почему вы используете float и real нужны ли вам точные значения.

2. Вы можете легко изменить тип данных столбца с помощью ALTER ; хотя, если в столбцах есть CONSTRAINTS и INDEX , вам нужно сначала DROP их изменить, а затем воссоздать заново. Кроме того, если есть какие-либо объекты schemabound, ссылающиеся на них, их также необходимо будет удалить и воссоздать заново.

3. Ваши исходные значения не являются точными — SSMS просто отображает их таким образом.

4. «Можно ли быстро выполнить эти изменения» технически вы могли бы использовать динамический оператор для ALTER них всех, но он, конечно, не будет учитывать какие-либо другие объекты, которые будут блокировать операцию. Что вы действительно хотели бы сделать, так это создать сценарий миграции в вашей среде разработки, чтобы у вас был большой пакет, который выполнял все изменения; и поскольку это разработчик, не имеет значения, что вы нарушаете. Что касается того, что произойдет во время ALTER работы с таблицей, запросы, скорее всего, будут заблокированы до завершения выполнения инструкции DDL.

5. float по-прежнему является неточным типом данных. Оба real и float есть.

Ответ №1:

Я в замешательстве, почему SSMS округляет реальные значения при их отображении, но не делает то же самое для значений с плавающей запятой

Ближайшим числом с плавающей запятой одинарной точности ( real ) к 2.1 является что-то вроде 2.09999999. Поэтому имеет смысл отобразить его как 2.1.

Ближайшее число с плавающей запятой двойной точности ( float ) к 2.1 довольно далеко от 2.0999990000000, что примерно соответствует тому, что вы получаете при преобразовании 2.0999999 из real float в.

SSMS будет отображать значения с плавающей запятой ближе к 2.1 как 2.1, например

 select cast(2.1 as float), cast(2.1 as float) - 0.000000000000001 
 

отображается в виде

 ---------------------- ----------------------
2.1                    2.1
 

Вот статья, в которой рассматриваются алгоритмы для этого преобразования и представлен новый: быстрая и точная печать чисел с плавающей запятой с помощью целых чисел

Ответ №2:

Так же, как дополнение к ответу Дэвида Брауна:

Похоже, прямое приведение вам не поможет. Вы можете получить «правильные» (лучшие) результаты, используя символьный тип, как следующий:

 select cast(cast(Valuef as nvarchar(20)) as float)
 

В качестве примера select cast(cast(cast(2.1 as real) as nvarchar(20)) as float) отображается просто 2.1 .