Как я могу «обрезать» C # до значения, которое будет храниться как в базе данных sqlite? - PullRequest
7 голосов
/ 17 ноября 2010

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

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

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

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

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

Ответы [ 6 ]

3 голосов
/ 03 декабря 2010

Ответом может быть сохранение двойных значений в виде 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 # и преобразовать ее обратно в исходное значение типа double.

2 голосов
/ 17 ноября 2010

Double round имеет реализацию с параметром, который указывает количество цифр. Используйте это, чтобы округлить до 14 цифр (скажем) с: rval = Math.Round (Val, 14)

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

Подробнее:

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

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

2 голосов
/ 17 ноября 2010

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

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

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

1 голос
/ 18 ноября 2010

Если вы хотите, чтобы десятичные входные значения были в обоих направлениях, вам придется ограничить их 15 значащими цифрами. Если вы хотите, чтобы значения с плавающей запятой в SQLite с внутренней точностью имели двойное значение, то вам может не повезти; для этого требуется печать не менее 17 значащих цифр, но, насколько я могу судить, SQLite печатает их максимум до 15 ( EDIT : , может быть, эксперт SQLite может подтвердить это? I просто прочитайте исходный код и отследите его - я был прав, точность ограничена 15 цифрами.)

Я протестировал ваш пример в командном интерфейсе SQLite в Windows. Я вставил 0.56657011973046234 и выбрал вернул 0.566570119730462. В C, когда я присвоил 0.566570119730462 для двойного и напечатал его до 17 цифр, я получил 0.56657011973046201; это то же самое значение, которое вы получаете от C #. Значения 0.56657011973046234 и 0.56657011973046201 соответствуют разным числам с плавающей запятой, поэтому, другими словами, SQLite double не выполняет циклическую обработку.

1 голос
/ 17 ноября 2010

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

1 голос
/ 17 ноября 2010

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...