Comment puis-je couper 'un C # double pour la valeur, il sera stocké comme dans une base de données SQLite?

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

Question

J'ai remarqué que lorsque je stocke une double valeur, comme par exemple x = 0.56657011973046234 dans une base de données SQLite, puis le récupérer plus tard, je reçois y = 0.56657011973046201. Selon la spécification sqlite et . spec NET (ni dont je l'origine pris la peine de lire :) cela est prévu et normal.

Mon problème est que si une grande précision est pas important, mes offres app avec les utilisateurs SAISIE / sélection doubles qui représentent les informations 3D de base, puis des simulations sur eux pour trouver un résultat. Et cette entrée peut être enregistrée dans une base de données SQLite pour être rechargé et Réexécutez plus tard.

La confusion se produit car une série d'entrées simule évidemment de manière légèrement différente de ces mêmes entrées fraîchement créé une fois stockés et rechargés (comme les doubles valeurs ont changé). Ce qui est logique, mais pas appréciable.

Je n'ai pas tout à fait venir à bout de la façon de traiter, mais en attendant, je voudrais limiter / bloquer les entrées de l'utilisateur à des valeurs qui peuvent être exactement stockées dans une base de données SQLite. Donc, si une des entrées utilisateur 0.56657011973046234, il est effectivement transformé en 0.56657011973046201.

Cependant, je ne l'ai pas été en mesure de comprendre, étant donné un certain nombre, quelle valeur serait stocké dans la base de données, à court de stockage réellement et le récupérer à partir de la base de données, ce qui semble maladroit. Y at-il une façon établie de le faire?

Était-ce utile?

La solution

Double tour a une mise en œuvre avec un paramètre qui spécifie le nombre de chiffres. Utilisez cette option pour arrondir à 14 chiffres (par exemple) avec: rval = Math.Round (Val, 14)

Ensuite, tour lors de la réception de la valeur de la base de données, et au début des simulations, par exemple. Donc, les valeurs correspondent?

Pour plus de détails:

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

Une autre pensée si vous ne comparez pas les valeurs dans la base de données, il suffit de les stocker: Pourquoi ne pas les stocker simplement des données binaires? Ensuite, tous les bits seraient stockés et récupérés in extenso?

Autres conseils

La réponse peut être à stocker les doubles valeurs 17 chaînes significatives de chiffres. Regardez la différence entre la façon dont SQLite gère les nombres réels par rapport texte (je vais illustrer avec l'interface de ligne de commande, pour simplifier):

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

Le stockage avec une affinité réelle est la cause de votre problème - SQLite ne vous rend une approximation de 15 chiffres. Si, au lieu de le stocker sous forme de texte, vous pouvez récupérer la chaîne d'origine avec votre programme C # et reconvertir à la double origine.

En supposant que les deux SQL Lite et .NET appliquent correctement la spécification IEEE, vous devriez être en mesure d'obtenir les mêmes résultats numériques si vous avez utilisé le même type de point flottant sur les deux côtés (parce que la valeur ne doit pas être modifiée lorsque passé de base de données à C # et vice versa).

À l'heure actuelle que vous utilisez à virgule flottante IEEE 8 octets (simple) (*) dans SQL Lite et 16 octets à virgule flottante en C # (double). Le type de float en C # correspond à la norme IEEE 8 octets, donc en utilisant ce type au lieu de double pourrait résoudre le problème.

(*) La documentation SQL Lite dit que REAL est une valeur en virgule flottante, stockée sous forme d'un nombre à virgule flottante IEEE 8 octets .

Vous pouvez utiliser une chaîne pour stocker le # dans la db. Personnellement, je l'ai fait ce que Winwaed a suggéré de l'arrondissement avant de le ranger et après l'extraction de la db (qui a utilisé numérique ()).

Je me souviens avoir été brûlé par les banquiers d'arrondissement, mais il pourrait être juste qui ne répondait pas aux spécifications.

Vous pouvez enregistrer la double sous forme de chaîne, et en utilisant le formatage aller-retour lors de la conversion double en une chaîne, il est garanti pour générer la même valeur lorsque analysable:

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

Si vous voulez que les valeurs d'entrée décimales à aller-retour, vous devrez les limiter à 15 chiffres significatifs. Si vous voulez les valeurs à double précision à virgule flottante interne SQLite à aller-retour, alors vous pourriez être hors de la chance; qui exige l'impression à un minimum de 17 chiffres significatifs, mais de ce que je peux dire, SQLite les imprime à un maximum de 15 ( EDIT : peut-être un expert SQLite peut confirmer Je viens de lire le code source et traça il -. J'avais raison, la précision est limitée à 15 chiffres)

Je l'ai testé votre exemple dans l'interface de commande SQLite sous Windows. Je ,56657011973046234 inséré, et sélectionnez retourné ,566570119730462. En C, quand je ,566570119730462 à un affecté double et imprimé à 17 chiffres, je suis arrivé 0,56657011973046201; c'est la même valeur que vous obtenez de C #. ,56657011973046234 et ,56657011973046201 carte à différents nombres à virgule flottante, donc en d'autres termes, la double SQLite ne pas aller-retour.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top