Recientemente tuve que serializar un doble en texto y luego recuperarlo. El valor parece no ser equivalente:
double d1 = 0.84551240822557006;
string s = d1.ToString("R");
double d2 = double.Parse(s);
bool s1 = d1 == d2;
// -> s1 is False
Pero según MSDN: cadenas de formato numérico estándar , se supone que la opción "R" garantiza la seguridad de ida y vuelta.
El especificador de formato de ida y vuelta ("R") se utiliza para garantizar que un valor numérico que se convierte en una cadena se analice nuevamente en el mismo valor numérico
¿Por qué pasó esto?
Respuestas:
Encontré el error.
.NET hace lo siguiente en
clr\src\vm\comnumber.cpp
:DoubleToNumber
es bastante simple: solo llama_ecvt
, que está en el tiempo de ejecución de C:Resulta que
_ecvt
devuelve la cadena845512408225570
.¿Nota el cero final? ¡Resulta que hace toda la diferencia!
Cuando el cero está presente, el resultado vuelve a analizar
0.84551240822557006
, que es sunúmero original , por lo que se compara igual y, por lo tanto, solo se devuelven 15 dígitos.Sin embargo, si trunco la cadena en ese cero
84551240822557
, entonces vuelvo0.84551240822556994
, que no es su número original, y por lo tanto devolvería 17 dígitos.Prueba: ejecute el siguiente código de 64 bits (la mayoría de los cuales extraje de Microsoft Shared Source CLI 2.0) en su depurador y examine
v
al final demain
:fuente
+1
. Este código es de shared-source-cli-2.0 ¿verdad? Este es el único pensamiento que encontré.Me parece que esto es simplemente un error. Sus expectativas son completamente razonables. Lo reproduje usando .NET 4.5.1 (x64), ejecutando la siguiente aplicación de consola que usa mi
DoubleConverter
clase.DoubleConverter.ToExactString
muestra el valor exacto representado por adouble
:Resultados en .NET:
Resultados en Mono 3.3.0:
Si especifica manualmente la cadena de Mono (que contiene el "006" en el extremo), .NET lo analizará nuevamente al valor original. Parece que el problema está en el
ToString("R")
manejo y no en el análisis.Como se señaló en otros comentarios, parece que esto es específico para ejecutarse bajo el CLR x64. Si compila y ejecuta el código anterior dirigido a x86, está bien:
... obtienes los mismos resultados que con Mono. Sería interesante saber si el error aparece en RyuJIT: no tengo eso instalado en este momento. En particular, puedo imaginar que esto posiblemente sea un error JIT, o es muy posible que haya implementaciones completamente diferentes de los componentes internos
double.ToString
basados en la arquitectura.Le sugiero que presente un error en http://connect.microsoft.com
fuente
ToString()
? Cuando intenté reemplazar el valor codificado conrand.NextDouble()
y no hubo ningún problema.ToString("R")
conversión. IntenteToString("G32")
y observe que imprime el valor correcto.Recientemente, estoy tratando de resolver este problema . Como se señaló a través del código , el double.ToString ("R") tiene la siguiente lógica:
En este caso, double.ToString ("R") eligió incorrectamente el resultado con una precisión de 15 para que ocurra el error. Hay una solución oficial en el documento de MSDN:
Por lo tanto, a menos que se resuelva este problema, debe usar double.ToString ("G17") para los viajes de ida y vuelta.
Actualización : ahora hay un problema específico para rastrear este error.
fuente