Как я могу «обрезать» двойник С# до значения, которое он будет хранить как в базе данных sqlite?

StackOverflow https://stackoverflow.com/questions/4200736

Вопрос

Я заметил, что когда я сохраняю двойное значение, например, x = 0.56657011973046234 в базе данных sqlite, а затем получить ее позже, я получаю y = 0.56657011973046201.Согласно спецификация sqlite и Спецификация .NET (ни то, ни другое я изначально не удосужился прочитать :) это ожидаемо и нормально.

Моя проблема в том, что, хотя высокая точность не важна, в моем приложении пользователи вводят/выбирают двойники, представляющие базовую трехмерную информацию, а затем запускают на них симуляцию, чтобы найти результат.И этот ввод можно сохранить в базе данных sqlite для перезагрузки и повторного запуска позже.

Путаница возникает потому, что недавно созданная серия входных данных, очевидно, будет моделировать несколько иначе, чем те же самые входные данные после сохранения и перезагрузки (поскольку значения double изменились).Это логично, но нежелательно.

Я еще не совсем понял, как с этим справиться, но тем временем я хотел бы ограничить/ограничить ввод пользователя значениями, которые могут быть точно сохранены в базе данных sqlite.Итак, если пользователь вводит 0.56657011973046234, он фактически преобразуется в 0.56657011973046201.

Однако мне не удалось выяснить, учитывая число, какое значение будет храниться в базе данных, за исключением фактического хранения и извлечения его из базы данных, что кажется неуклюжим.Есть ли устоявшийся способ сделать это?

Это было полезно?

Решение

Двойной раунд имеет реализацию с параметром, который указывает количество цифр. Используйте это, чтобы раунд до 14 цифр (скажем) с: RVAL = MATH. RUOND (VAL, 14)

Затем вокруг при получении значения из базы данных и в начале моделирования, т. Е. Так что на значении совпадают?

Подробнее:

http://msdn.microsoft.com/en-us/library/75ks3aby.aspx.

Еще одна мысль, если вы не сравниваете значения в базе данных, просто храняте их: почему бы не просто хранить их как двоичные данные? Тогда все биты будут храниться и восстановлены дословно?

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

Ответ может быть для хранения двойных значений как 17 важных цифровых строк. Посмотрите на разницу между тем, как SQLite обрабатывает реальные числа против текста (я проиллюстрирую с интерфейсом командной строки, для простоты):

sqlite> create table t1(dr real, dt varchar(25));
sqlite> insert into t1 values(0.56657011973046234,'0.56657011973046234');
sqlite> select * from t1;
0.566570119730462|0.56657011973046234

Хранение его реальной близости - это причина вашей проблемы - SQLite дает вам только 15-значное приближение. Если вместо этого вы храните его как текст, вы можете получить исходную строку с помощью своей программы C # и преобразовать его обратно в оригинальный двойной.

Предполагая, что и SQL Lite, и .NET правильно реализуют спецификацию IEEE, вы сможете получить одинаковые числовые результаты, если используете один и тот же тип с плавающей запятой с обеих сторон (поскольку значение не должно изменяться при передаче из базы данных). на C# и наоборот).

В настоящее время вы используете 8-байтовую плавающую запятую IEEE (одинарную) (*) в SQL Lite и 16-байтовую плавающую запятую в C# (двойную).А float тип в C# соответствует 8-байтовому стандарту IEEE, поэтому использование этого типа вместо double мог бы решить проблему.

(*) В документации SQL Lite сказано, что REAL — это значение с плавающей запятой, сохраненное как 8-байтовое число с плавающей запятой IEEE.

Вы можете использовать строку для хранения # в БД. Лично я сделал то, что Winwaed предложил округление перед хранением и после получения из БД (который использовал числовую ()).

Я помню, как сожжен закругление банкиров, но это может быть просто не соответствует спецификации.

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

string formatted = theDouble.ToString("R", CultureInfo.Invariant);

Если вы хотите, чтобы десятичные входные значения в Round-Trip, вы должны ограничить их до 15 важных цифр. Если вы хотите, чтобы SQLite внутренние значения с плавающей точкой с двойной точностью в туристическую поездку вы можете быть удачи; Это требует печати минимум 17 важных цифр, но из того, что я могу сказать, SQLite печатает их максимум 15 (РЕДАКТИРОВАТЬ: Может быть, SQLite Expert может подтвердить это? Я просто прочитал исходный код и проследил его - я был правильным, точность ограничена 15 цифрами.)

Я проверил ваш пример в интерфейсе SQLite Command на Windows. Я вставил 0,56657011973046234, и выберите Возвращенное 0.566570119730462. В C, когда я назначил 0,566570119730462 в двойную и напечатал его до 17 цифр, я получил 0,56657011973046201; Это то же значение, которое вы получаете от C #. 0.56657011973046234 и 0.56657011973046201 Карта на различные номера с плавающей точкой, так, другими словами, SQLite Double не работает.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top