Wie kann ich eine C # doppelt auf den Wert ‚schneiden‘ wird es wie in einer SQLite-Datenbank gespeichert werden?

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

Frage

Ich habe bemerkt, dass, wenn ich speichere einen doppelten Wert wie z.B. x = 0.56657011973046234 in einer SQLite-Datenbank, und dann rufen Sie sie später, ich y = 0.56657011973046201 bekommen. Nach dem SQLite spec und die . NET spec (weder von dem ich ursprünglich zu lesen gestört :) dies erwartet wird und normal.

Mein Problem ist, dass, während eine hohe Präzision nicht wichtig ist, meine App beschäftigt sich mit Benutzer-Eingabe / Auswahl verdoppelt, die grundlegenden 3D-Informationen darstellen, und dann Simulationen auf ihnen laufen, ein Ergebnis zu finden. Und kann dieser Eingang zu einer SQLite-Datenbank gespeichert werden, werden neu geladen und wieder laufen später.

Die Verwirrung tritt auf, weil eine frisch erstellten Reihe von Eingaben wird natürlich etwas andere Art und Weise zu den gleichen Eingaben simuliert einmal gespeichert und wieder geladen wird (wie die Doppelwerte geändert haben). Dies ist logisch, aber nicht wünschens.

Ich habe nicht ganz zu Sachen kommt, wie man damit umgehen, aber in der Zwischenzeit würde ich zu begrenzen mag / klemmen Sie die Benutzereingaben auf Werte, die in einer SQLite-Datenbank gespeichert werden, genau können. Also, wenn ein Benutzer Eingaben 0.56657011973046234, wird es tatsächlich in 0.56657011973046201 umgewandelt.

Allerdings habe ich nicht in der Lage gewesen, um herauszufinden, da eine Zahl, welcher Wert in der Datenbank gespeichert werden würde, kurz tatsächlich zu speichern und sie aus der Datenbank abrufen, die klobig zu sein scheint. Gibt es eine etablierte Art und Weise, dies zu tun?

War es hilfreich?

Lösung

Doppelrunde hat eine Implementierung mit einem Parameter, der angibt, die Anzahl der Ziffern. Verwenden Sie diese zu Runde zu 14 Stellen (sagen wir) mit: rval = Math.Round (Val, 14)

Dann Runde, wenn der Wert aus der Datenbank zu empfangen und zu Beginn der Simulation, dh. Also auf die Werte übereinstimmen?

Für Einzelheiten:

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

Ein weiterer Gedanke, wenn Sie nicht Werte in der Datenbank zu vergleichen, nur um sie zu speichern: Warum lagern Sie sie nicht einfach als binäre Daten? Dann werden alle Bits gespeichert würden und wiederhergestellt wörtlich?

Andere Tipps

Die Antwort kann die doppelten Werte als 17 signifikante Ziffernfolgen zu speichern sein. Schauen Sie sich die Differenz zwischen dem, wie SQLite Griffe reellen Zahlen vs. Text (I mit der Befehlszeilenschnittstelle, der Einfachheit halber veranschaulichen werden):

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

es mit echten Affinität zu speichern ist die Ursache des Problems - SQLite gibt nur Sie eine 15-stellige Annäherung zurück. Wenn Sie stattdessen als Text speichern, können Sie die ursprüngliche Zeichenfolge mit C # -Programm abrufen und wandeln es wieder in die ursprünglichen Doppel.

Unter der Annahme, dass sowohl SQL Lite und .NET korrekt die IEEE-Spezifikation implementieren, sollten Sie in der Lage sein, die gleichen numerischen Ergebnisse zu erhalten, wenn Sie die gleiche Gleitkommatyps auf beide der Seiten verwendet wird (weil der Wert nicht verändert werden soll, wenn geben kehrt von Datenbank zu C # und vice).

Zur Zeit Sie verwenden 8-Byte IEEE-Gleitkomma (single) (*) in SQL Lite und 16-Byte-Gleitkommazahlen in C # (double). Der float Typ in C # entspricht den 8-Byte IEEE-Standard zu verwenden, da diese Art statt double könnte das Problem lösen.

(*) Die Dokumentation SQL Lite sagt, dass REAL ist ein Gleitkommawert, gespeichert als 8-Byte IEEE Gleitkommazahl .

Sie können eine Zeichenfolge verwenden, um die # in der Db zu speichern. Persönlich habe ich das getan, was winwaed der Rundung vorgeschlagen vor der Lagerung und nach aus dem db holen (die numerischen verwendet ()).

Ich erinnere mich von Bankern verbrannt Runden, aber es könnte nur sein, dass nicht treffen spec hat.

Sie können speichern die doppelte als String, und durch die Hin- und Rückfahrt mit der Formatierung, wenn die doppelte Konvertierung in einen String, ist es garantiert den gleichen Wert zu erzeugen, wenn analysiert:

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

Wenn Sie die Dezimaleingabe Werte Round-Trip wollen, dann werden Sie sie auf 15 signifikante Stellen zu begrenzen. Wenn Sie die SQLite interne doppeltgenaue Fließkommawerte zu Round-Trip wollen, dann könnten Sie kein Glück; , die auf ein Minimum von 17 signifikanten Stellen erfordern Druck, aber von dem, was ich sagen kann, SQLite druckt sie auf maximal 15 ( Bearbeiten : vielleicht ein SQLite Experte kann dies bestätigen ich habe gerade gelesen, den Quellcode und verfolgt sie. - ich war richtig, ist die Genauigkeit auf 15 Stellen beschränkt)

teste ich dein Beispiel in der SQLite-Befehlsschnittstelle unter Windows. I eingefügt 0,56657011973046234, und wählen 0,566570119730462 zurückgegeben. In C, wenn I 0,566570119730462 zu einem Doppel zugeordnet und ausgedruckt, es zu 17 Ziffern, habe ich ,56657011973046201; Das ist der gleiche Wert, den Sie von C # zu bekommen. 0,56657011973046234 und ,56657011973046201 Karte auf verschiedene Gleitkommazahlen, also mit anderen Worten, die SQLite Doppel nicht Round-Trip.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top