Как я могу «обрезать» двойник С# до значения, которое он будет хранить как в базе данных sqlite?
-
25-09-2019 - |
Вопрос
Я заметил, что когда я сохраняю двойное значение, например, 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 не работает.