¿Cómo puedo recortar '' un C # doble al valor que se almacenará como en una base de datos SQLite?

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

Pregunta

I notado que cuando almacenar un valor doble tal como por ejemplo x = 0.56657011973046234 en una base de datos SQLite, y luego recuperarlo más tarde, consigo y = 0.56657011973046201. De acuerdo con la sqlite spec y la . NET especificación (ninguno de los cuales que originalmente molestado en leer :) se espera y normal.

Mi problema es que mientras que la alta precisión no es importante, mis ofertas aplicación con la introducción de los usuarios / selección de dobles que representan información básica 3D, y luego ejecutar simulaciones sobre ellos para encontrar un resultado. Y esta entrada se puede guardar en una base de datos SQLite que volver a cargar y volver a ejecutar más tarde.

La confusión se produce porque una serie recién creados de los insumos, obviamente, simular en forma ligeramente diferente a las mismas entradas, una vez almacenados y recargados (como los valores dobles han cambiado). Esto es lógico, pero no deseable.

He no es llegar a un acuerdo de cómo hacer frente a esto, pero mientras tanto me gustaría límite / sujetar las entradas del usuario a los valores que se pueden almacenar exactamente en una base de datos SQLite. Así que si un usuario introduce 0.56657011973046234, en realidad se transforma en 0.56657011973046201.

Sin embargo no he podido averiguar, dado un número, ¿qué valor se almacena en la base de datos, a falta de realidad almacenar y recuperar desde la base de datos, lo que parece torpe. ¿Hay una forma establecida de hacer esto?

¿Fue útil?

Solución

ronda doble tiene una aplicación con un parámetro que especifica el número de dígitos. Utilice esta ronda de 14 dígitos (por ejemplo) con: rval = Math.Round (Val, 14)

Entonces ronda cuando se recibe el valor de la base de datos, y al comienzo de las simulaciones, es decir. Así que a los valores coinciden?

Para más detalles:

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

Otro pensamiento si no está comparando los valores en la base de datos, simplemente almacenarlos: ¿Por qué no simplemente guardarlas como datos binarios? A continuación, todos los bits se almacenan y se recuperan pie de la letra?

Otros consejos

La respuesta puede ser para almacenar los valores dobles, 17 cuerdas dígitos significantes. Vistazo a la diferencia entre la forma en SQLite maneja números reales vs. texto (voy a ilustrar con la interfaz de línea de comandos, para simplificar):

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

Su almacenamiento con una afinidad real es la causa de su problema - SQLite sólo se le da una copia de una aproximación de 15 dígitos. Si en lugar de guardarlo como texto, puede recuperar la cadena original con su programa en C # y convertirlo de nuevo a la original doble.

Si se asume que tanto SQL Lite y .NET implementar correctamente la especificación IEEE, que debe ser capaz de obtener los mismos resultados numéricos si se ha utilizado el mismo tipo de punto flotante en ambos de los lados (porque el valor no debe ser alterada cuando pasado de base de datos para C # y viceversa).

En la actualidad se está utilizando en coma flotante de 8 bytes IEEE (individual) (*) en SQL Lite y 16 bytes de punto flotante en C # (doble). El tipo float en C # se corresponde con el estándar IEEE de 8 bytes, por lo que el uso de este tipo en lugar de double podría resolver el problema.

(*) La documentación de SQL Lite dice que el Madrid es un valor de punto flotante, se almacena como un número de coma flotante de 8 bytes IEEE .

Se puede utilizar una cadena para almacenar el # en el PP. Personalmente he hecho lo que sugiere Winwaed de redondeo antes de guardarlo y después de ir a buscar desde el PP (que utiliza numérico ()).

Yo recuerdo estar quemado por los banqueros de redondeo pero podría ser que no lo hizo especificaciones se encuentran.

Se puede almacenar el doble como una cadena, y mediante el uso de la ida y vuelta en el formato al convertir el doble para una cadena, está garantizado para generar el mismo valor cuando analizada:

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

Si desea que los valores de entrada decimales a ida y vuelta, entonces usted tiene que limitar a 15 dígitos significativos. Si desea que los valores de punto flotante del SQLite doble precisión interna a ida y vuelta, entonces usted podría estar fuera de suerte; que requiere la impresión de un mínimo de 17 dígitos significativos, pero por lo que puedo decir, SQLite los imprime un máximo de 15 ( Editar : tal vez un experto SQLite puede confirmar esto Acabo de leer el código fuente y rastreé -. yo era correcta, la precisión está limitada a 15 dígitos)

He probado su ejemplo en el interfaz de comandos de SQLite en Windows. He insertado 0.56657011973046234 y seleccione regresar ,566570119730462. En C, cuando me asignaron ,566570119730462 a un doble y imprimí a 17 dígitos, llegué ,56657011973046201; ese es el mismo valor que se obtiene de C #. 0.56657011973046234 y ,56657011973046201 mapa a diferentes números de punto flotante, por lo que en otras palabras, el SQLite no cumple una doble ida y vuelta.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top