Как я могу "обрезать" c# double до значения, которое будет храниться как в базе данных sqlite?

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

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

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

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

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

6 ответов


Double round имеет реализацию с параметром, который определяет количество цифр. Используйте это, чтобы округлить до 14 цифр (скажем) с: rval = Math.Круглая(Вал, 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 (single) (*) в SQL Lite и 16-байтовую плавающую точку в C# (double). The float тип в C# соответствует 8-байтовому стандарту IEEE, поэтому использование этого типа вместо double может решить проблему.

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


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

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


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

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

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

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